Problem, normalen RMI Client auf JBoss zum Laufen zu bekommen

Klanthe

Grünschnabel
Hallo,

ich versuche eine reine RMI-Anwendung (kein EJB, kein Webservice, etc.) auf Jboss 4.0 zum Laufen zu kriegen. Irgendwie wills nicht klappen.

Ich benutze Eclipse WTP 3.x...

Die Serviceklasse beinhaltet eine Start-Methode, welche den Service in der RMI-Registry registrieren soll. Dies funktioniert auch, wenn ich über das RMI-Plugin die lokale RMI-Registry starte (ist die Standard-RMI Registry von Sun).

Der Client holt sich dann den Service über rmi://localhost:1099/ppsTestService
und der RMI-Inspector des Plugins zeigt den installierten Service auf localhost:1099 auch an.

Versuche ich aber den Service auf jboss zum laufen zu bekommen, so gelingt dies nicht.
Ich habe nun versucht den Service über JNDI zu binden. Das lookup() scheint ihn auch zu finden, aber wenn ich dann eine Methode aufrufen will, dannn bekomme ich eine Excedption: connection refused.

Vermutlich muss ich die RMI-Serviceklasse ganz anders deployen. Kann mir da jemand einen Tip geben?

Hier der Servercode, der mit der RMI-Registry funktioniert:

Code:
public class PPSTestServiceImpl
	implements PPSTestService
{
  
	public PPSTestServiceImpl()
	{
	}


	/**
	 * Methode registriert diesen Service unter dem Namen ppsTestService am RMI-Server
	 *
	 */
	private void start() {
		
		try {
    		PPSTestService serviceStub = (PPSTestService) UnicastRemoteObject.exportObject(this);
    		Registry registry = LocateRegistry.getRegistry();
    		registry.rebind("ppsTestService", serviceStub);
		} catch (RemoteException e) {
      // TODO Sinnvolle Exception ausgeben
          e.printStackTrace();
		}
	}

	/**
	 * Methode startet den Testservice, indem es die Registrierungsmethode des Service aufruft
	 * @param args
	 */
	public static void main(String[] args) {
		new PPSTestServiceImpl().start();
	}

	/**
	 * Testimplementierung einer Serviceroutine, welche die	aktuelle Uhrzeit liefert
	 */
	public String getTime()
	throws RemoteException
	{
		GregorianCalendar cal = new GregorianCalendar();
		StringBuffer sb = new StringBuffer();
		sb.append(cal.get(Calendar.HOUR_OF_DAY));
		sb.append(":" + cal.get(Calendar.MINUTE));
		sb.append(":" + cal.get(Calendar.SECOND));
		return sb.toString();
	}
}


Und hier der Client dazu:

Code:
public class PPSTestServiceClient
{
  public static void main(String[] args)
  {
     try{
      String host = "localhost";
      String port = "1099";
      String srv  = "ppsTestService";
      String url = "rmi://" + host + ":" + port + "/" + srv;
      
      System.out.println("Looking-up PPSTestService " + url);
      PPSTestService ts = (PPSTestService)Naming.lookup(url); 
      
      System.out.println("  Server time is " + ts.getTime()); 

     } catch (Exception e) {
         System.err.println(e.toString());
         System.exit(1);
    }

  }

Meine Frage: Wie bekomme ich das unter Jboss ans laufen?
Starte ich den JBoss, und versuche die Registrierung auf den gleichen Weg, erhalte ich die folgende Fehlermeldung auf der Console:

Code:
java.rmi.ConnectIOException: error during JRMP connection establishment; nested exception is: 
	java.net.SocketException: Software caused connection abort: recv failed
	at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:273)
	at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:171)
	at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:306)
	at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)
	at de.pbs.testautomat.impl.PPSTestServiceImpl.start(PPSTestServiceImpl.java:60)
	at de.pbs.testautomat.impl.PPSTestServiceImpl.main(PPSTestServiceImpl.java:72)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:585)
	at net.genady.rmi.logger.Runner.main(Runner.java:137)
Caused by: java.net.SocketException: Software caused connection abort: recv failed
	at java.net.SocketInputStream.socketRead0(Native Method)
	at java.net.SocketInputStream.read(SocketInputStream.java:129)
	at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
	at java.io.BufferedInputStream.read(BufferedInputStream.java:235)
	at java.io.DataInputStream.readByte(DataInputStream.java:241)
	at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:215)
	... 10 more

Was muss ich tun, um diese Klasse unter JBoss korrekt zu deployen und zu registrieren?

Vielen Dank im Voraus,
Mike
 

Thomas Darimont

Erfahrenes Mitglied
Hallo,

IMHO verlangt die Remoting Infrastruktor von JBoss hier ein anderes vorgehen.
Anstatt über die RMIRegistry kannst du hier über das JNDI gehen.

Beispiel:
Unser ITimeService-Interface:
Java:
/**
 * 
 */
package de.tutorials.training.jboss.services;

import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.Date;

/**
 * @author Tom
 *
 */
public interface ITimeService extends Remote {
  Date getTime() throws RemoteException;
}

Unsere Implementierung:
Java:
/**
 * 
 */
package de.tutorials.training.jboss.server.services;

import java.util.Date;

import de.tutorials.training.jboss.services.ITimeService;

/**
 * @author Tom
 *
 */
public class TimeService implements ITimeService{
  public Date getTime() {
    System.out.println("getTime()");
    return new Date();
  }
}

Bootstrappen tun wir unseren TimeService über ein entsprechendes MBean:
Java:
/**
 * 
 */
package de.tutorials.training.jboss.server;

/**
 * @author Tom
 *
 */
public interface TimeServiceAdministrationMBean {
  void start();
  void stop();  
}

Unsere MBean Implementierung:
Java:
/**
 * 
 */
package de.tutorials.training.jboss.server;

import java.rmi.server.UnicastRemoteObject;

import javax.naming.InitialContext;

import de.tutorials.training.jboss.server.services.TimeService;
import de.tutorials.training.jboss.services.ITimeService;

/**
 * @author Tom
 */
public class TimeServiceAdministration implements
		TimeServiceAdministrationMBean {
	ITimeService timeService;

	public void start() {
		if (null == this.timeService) {
			try {
				System.out.println("exportObject");
				this.timeService = (ITimeService) UnicastRemoteObject
						.exportObject(new TimeService(), 0);
				System.out.println("bind");
				InitialContext initialContext = new InitialContext();
				initialContext.rebind(ITimeService.class.getName(),
						this.timeService);
				initialContext.close();
			} catch (Throwable e) {
				e.printStackTrace();
			}
		} else {
			System.out.println("TimeService is already started");
		}
	}

	public void stop() {
		if (null != this.timeService) {
			try {
				System.out.println(this.timeService);
				System.out.println("unbind");
				InitialContext initialContext = new InitialContext();
				initialContext.unbind(ITimeService.class.getName());
				System.out.println("unbind successfull");
				this.timeService = null;
				initialContext.close();
			} catch (Throwable t) {
				t.printStackTrace();
			}
		} else {
			System.out.println("TimeService is not started");
		}
	}
}

Hier noch unser MBean Descriptor jboss-service.xml (muss im .sar File im META-INF Verzeichnis liegen)
XML:
<?xml version="1.0" encoding="UTF-8"?>
<server>
  <mbean code="de.tutorials.training.jboss.server.TimeServiceAdministration"
         name="de.tutorials:service=TimeServiceAdministration,type=example">
         <operation>
             <name>start</name>
             <return-type>java.lang.Void</return-type>
         </operation>
         
         <operation>
             <name>stop</name>
             <return-type>java.lang.Void</return-type>
         </operation>
  </mbean>
</server>

Den ganzen kram exportieren wir nun in ein .sar (ServiceARchive) File und deployen es auf dem JBoss (einfach ins deploy Verzeichnis der entsprechenden Serverkonfiguration kopieren)

Hier nun unser Client:
Java:
/**
 * 
 */
package de.tutorials.training.jboss.client;

import javax.naming.InitialContext;

import de.tutorials.training.jboss.services.ITimeService;

/**
 * @author Tom
 * 
 */
public class Main {
    /**
     * @param args
     */
    public static void main(String[] args) throws Exception {
        InitialContext initialContext = new InitialContext();
        ITimeService timeService = (ITimeService) initialContext
                .lookup(ITimeService.class.getName());
        System.out.println(timeService.getTime());
        initialContext.close();
    }
}
(Der Client braucht das ITimeService-Interface im Classpath) Außerdem muss die Datei jndi.properties im Classpath liegen (findet man Beispielsweise unter: %JBOSS_HOME%/bin/ im twiddle.jar (einfach mit Winzip öffnen)
Diese Datei hat folgenden Inhalt:
Code:
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=jnp://localhost:1099
Diese muss gegebenenfalls (anderer Server) anpassen.

Anschließend kanns schon losgehen.
In der JMX Console unter (Beispielsweise) http://localhost:8080/jmx-console findet man unter de.tutorials nun unser TimeServiceAdministration MBean mit dem man den TimeService über starten und stoppen kann.

Gruß Tom
 

Anhänge

  • de.tutorials.jboss-rmi.zip
    13,1 KB · Aufrufe: 150
Zuletzt bearbeitet von einem Moderator:

Klanthe

Grünschnabel
Hallo Tom,

vielen Dank für Deine Tips.
Da ich nicht so tief in den speziellen JBoss-Techniken stecke, wäre ich darauf ohne Hilfe nie gekommen.
Den JNDI-Ansatz hatte ich schon vermutet, wußte aber nicht, wie ich ein - nicht EJB - derart auf JBoss Deployen könnte.
Ich werde das mal so ausprobieren.

Auf der anderen Seite soll JBoss hier nur als Entwicklerplattform genutzt werden, das Life-System ist später Bea-Weblogic.

Vielleicht sollte ich das Ganze dann doch lieber als normalen Webservice implementieren.

Nette Grüße,
Michael
 

acronym

Mitglied
Hallo,

das Beispiel liest sich gut, wird wohl auch sicher funktionieren.
Ist es möglich das Beispiel auch mit einem Stateless Session Bean zu implementieren?
Muss ich einen Dienst bereitstellen oder reicht dann ein lookup()?
Zudem bräuchte ich einen EJB als Client für einen plain Java RMI-Server ...
Gibt es eine Quelle in der beschrieben wird wie sowas geht?

mmmh, viele Fragen :)

Würde mcih über einen Tip freuen!

Grüße
Holger
 

timba07

Grünschnabel
Hi Leute,

ich habe ein ähnliches Problem. Ich möchte eine EJB3 basierte Applikation (ich benutze das SEAM Framework) mit einem reinen J2SE Server über RMI verbinden! Den Ansatz den RMI Server über ein MBEAN Service zu verwalten klingt gut und ich würde es gerne ausprobieren, jedoch habe ich absolut keine Ahnung wie ich ein Service Archive builde / deploye!! Ich habe eine Anleitung gefunden die auf einem 1000Zeilen ANT-Script basiert, welches man nat. an seine Wünsche anpassen müsste. Meine Frage nun, geht das nicht auch einfacher, vielleicht über ein IDE-Plugin (Eclipse)

Über Hilfe wäre wirklich dankbar.

*edit* Ich habe jetzt ein sar erstellt, dass genau den gleichen Aufbau wie deine sar-Datei zeigt. Leider bekomme ich bei Verwendung des sars als exploded Archive immer die folgende Ex: "org.jboss.deployment.DeploymentException: Class does not expose a management interface: java.lang.Object - nested throwable: (javax.management.NotCompliantMBeanException: Class does not expose a management interface: java.lang.Object".
Als .sar-Archiv bekomme ich gar "org.jboss.deployment.DeploymentException: Failed to find META-INF/jboss-service.xml"

Hier meine jboss-service.xml:

Code:
<?xml version="1.0" encoding="UTF-8"?>
<server>
   <mbean code="de.cohones.lasor.mcs.ManagementAdmin"         
		name="de.cohones.lasor.mcs:service=ManagementAdmin">         
		<operation>             
			<name>start</name>             
			<return-type>java.lang.Void</return-type>         
		</operation>      
		
		<operation>             
			<name>stop</name>             
			<return-type>java.lang.Void</return-type>         
		</operation>  
	</mbean>
</server>

Meine Ordnerstruktur:

- Class-Files in /de/cohones/lasor/mcs
- jboss-service.xml in /META-INF/

Das interessante ist, dass es mit deinem(Thomas') Testbeispiel funktioniert. Der Fehler muss also bei mir liegen! Was könnte ich falsch machen?

Grüße,
Stefan
 
Zuletzt bearbeitet:

timba07

Grünschnabel
Hallo,

Muss ich einen Dienst bereitstellen oder reicht dann ein lookup()?
Zudem bräuchte ich einen EJB als Client für einen plain Java RMI-Server ...
Gibt es eine Quelle in der beschrieben wird wie sowas geht?

Holger

Gibt es eigentlich eine Lösung für die Frage von Acronym? Denn genau das gleiche versuche ich auch. Und den plain RMI-Server wie in dem Beispiel in den AS zu integrieren würde ich nur als Notlösung nehmen wollen.

Grüße,
Stefan
 

timba07

Grünschnabel
Hi, die Namenskonvention habe ich beachtet. Mein Interface heißt "ManagementAdminMBean" und die Implementierung "ManagementAdmin". Daran sollte es also eigentlich nicht liegen, oder?

Die MBean Konfig habe ich auch bereits ausführlich getestet, ohne Erfolg. Das einzige was ich dabei nicht nachvollziehen konnte ist der Inhalt des Attributs "name" und dem Wert "type=example"! Daran sollte es aber auch nicht liegen! :(

Ich stehe wirklich auf dem Schlauch.
Auf Grund der Exceptions gehe ich davon aus, dass ich irgendetwas beim packen des SAR's falsch gemacht habe. Ich kann mir aber nicht erkären was! :( Hast du ein bestimmtes Tool für das Erstellen des SAR's benutzt? Letzendlich ist es doch nichts weiter als ein .JAR mit einer definierten Ordnerstruktur oder irre ich mich da? :confused:

Grüße,
Stefan
 

Andreas Martin

Grünschnabel
Vielen Dank Thomas Darimont.

edit:

Wie könnte man das gleiche Beispiel auf JBoss 7.1 laufen lassen?

Ich vermute das hier jboss-service.xml umgewandelt werden müsste.

Wenn ich einfach die timeservice.sar in JBoss 7.1 deploye, so kriege ich beim Deployment folgende Exception:

Code:
13:49:01,389 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-8) MSC00001: Failed to start service jboss.deployment.unit."timeservice.sar".PARSE: org.jboss.msc.service.StartException in service jboss.deployment.unit."timeservice.sar".PARSE: Failed to process phase PARSE of deployment "timeservice.sar"
	at org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:119) [jboss-as-server-7.1.1.Final.jar:7.1.1.Final]
	at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1811) [jboss-msc-1.0.2.GA.jar:1.0.2.GA]
	at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1746) [jboss-msc-1.0.2.GA.jar:1.0.2.GA]
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) [rt.jar:1.6.0_20]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) [rt.jar:1.6.0_20]
	at java.lang.Thread.run(Thread.java:619) [rt.jar:1.6.0_20]
Caused by: org.jboss.as.server.deployment.DeploymentUnitProcessingException: JBAS017224: Failed to parse service xml ["/C:/JBoss/server/jboss-as-7.1.1.Final/bin/content/timeservice.sar/META-INF/jboss-service.xml"]
	at org.jboss.as.service.ServiceDeploymentParsingProcessor.deploy(ServiceDeploymentParsingProcessor.java:95)
	at org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:113) [jboss-as-server-7.1.1.Final.jar:7.1.1.Final]
	... 5 more
Caused by: java.lang.IllegalStateException: Not a textual event (START_ELEMENT)
	at com.ctc.wstx.sr.BasicStreamReader.throwNotTextual(BasicStreamReader.java:5444)
	at com.ctc.wstx.sr.BasicStreamReader.getText(BasicStreamReader.java:833)
	at org.jboss.staxmapper.XMLExtendedStreamReaderImpl.getText(XMLExtendedStreamReaderImpl.java:275) [staxmapper-1.1.0.Final.jar:1.1.0.Final]
	at org.jboss.as.service.descriptor.JBossServiceXmlDescriptorParser.unexpectedContent(JBossServiceXmlDescriptorParser.java:622)
	at org.jboss.as.service.descriptor.JBossServiceXmlDescriptorParser.parseMBean(JBossServiceXmlDescriptorParser.java:260)
	at org.jboss.as.service.descriptor.JBossServiceXmlDescriptorParser.readElement(JBossServiceXmlDescriptorParser.java:183)
	at org.jboss.as.service.descriptor.JBossServiceXmlDescriptorParser.readElement(JBossServiceXmlDescriptorParser.java:46)
	at org.jboss.staxmapper.XMLMapperImpl.processNested(XMLMapperImpl.java:110) [staxmapper-1.1.0.Final.jar:1.1.0.Final]
	at org.jboss.staxmapper.XMLMapperImpl.parseDocument(XMLMapperImpl.java:69) [staxmapper-1.1.0.Final.jar:1.1.0.Final]
	at org.jboss.as.service.ServiceDeploymentParsingProcessor.deploy(ServiceDeploymentParsingProcessor.java:88)
	... 6 more
 

Andreas Martin

Grünschnabel
Ich habe zu dem Beispiel von Thomas Darimont ein Diagramm gemacht um es besser zu verstehen.

Bitte um Korrekturhinweise, falls was nicht stimmt.

Ich habe auch yEd-Datei angehängt, falls jemand daran selbst was machen möchte.

de.tutorials.jboss-rmi.JPG
 

Anhänge

  • de.tutorials.jboss-rmi.rar
    2,3 KB · Aufrufe: 11