Child pages
  • RMI alkalmazás fejlesztése
Skip to end of metadata
Go to start of metadata

Tisztelt nagyérdemű!

Szeretném, hogy a kliens alkalmazás elérje a szerver néhány metódusát, ill. változóját, amellett, hogy mindkét oldal egyazon pc-n fut. RMI-vel megoldható ez?

A JBuilderben ismerkedem egy neten talált példával: http://www.cab.u-szeged.hu/WWW/java/kiss/rmi.html

A szerver indítsakor akad meg, úgy gondolom, hogy a Naming() beállításai lehetnek rosszak. Így néz ki:

AlarmServerImpl server = new AlarmServerImpl("AlarmServer");
Naming.rebind("rmi://localhost:1099/AlarmServer", server);

Az RMIRegistry el van indítva! A szerver- és kliens csonk is le va generálva.

Kérlek segítsetek! Lehetőség szerint példákal is...

Köszönettel:
Z

      
      
Page viewed times
#trackbackRdf ($trackbackUtils.getContentIdentifier($page) $page.title $trackbackUtils.getPingUrl($page))
  • No labels

16 Comments

  1. Unknown User (kedzol)

    Szia,

    köszönet az előző témában nyújtott segítségért! És ím itt a következő gond: Az RMIServer futtatja a MainScene nevű osztályt, amely tartalmazza a Java3D virtuális világot... A kliensnek ezt át akarom adni. A kapcsolat fel is épül, csak az átvitel nem sikeres, kapok egy ilyen hibaüzenetet:
    java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
    java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: ww_ii_online.MainScene
    tehát Serializálhatóvá teszem a MainScene osztályt, de ekkor:
    java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
    java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: javax.media.j3d.BoundingSphere
    Meddig menjek el, az Object-ig???? :(

    Ugyanez a helyzet áll elő, mikor az adatbázist akarom átadni. Miután az adb-t tartalmazó csomagom összes osztálya serializálható lett, akkor elindul egy szinttel feljebb... Mi a megoldás?

    Kérlek segítsetek!!
    üdv
    Z
  2. Az RMI-hez nem nagyon szagolok, de például a JAX-RPC esetén (ami olyasmi, mint az RMI, csak SOAP alapú) csak olyan osztályt lehet átvinni, amit XML formátumba tud hozni. Élő adatbázis kapcsolatot vagy egy összetett példányszerkezetet nem lehet átvinni, mert ezek állandó interakciót igényelnek... érdemes úgy elkészíteni a távolról meghívott metódusokat, hogy primitív típusok burkoló osztályait adják csak vissza (plusz String)... ezekkel biztos működik.

    Értelemszerűen mindent távolról meghívott metódus paraméterlistájában és visszatérési értékében lévő osztálynak implementálnia kell a  Serializable interfészt... Egy picit mesélhetnél a projektedről, hátha jobban el tudunk igazodni a poblémádban... :)
  3. Helló,

    van még egy varázsszó, amit érdemes ismerni, ez pedig a "transient". Ha van egy osztályod, ami olyan másik objektumhoz csatlakozik amit már nem akarsz átküldeni az RMI-n akkor a transient módosítót kell használni. Pl:
    public class MyObject {
        //adatbázis kapcsolat
        private transient java.sql.Connection conn;
        // ...
    }
    Ekkor a "conn" objektum és az összes hozzá kapcsolódó objektum (gyakorlatilag az egész adatbázisszerver) nem lesz átküldve a hálózaton, hanem default értéket kap a másik oldalon. (null) Ebből adódik, hogy a másik oldalon a MyObject-nek nem tudod elérni a teljes funkcionalitását. Úgyhogy először is át kell gondolni, hogy melyek azok az objektumok amiket okvetlenül át akarsz nyomni a hálózaton és mi az amit távoli elérésre akarsz szánni.

    A másik dolog, hogyha teljes osztálykönyvtárakat akarsz átadni, akkor codebase-t érdemes megadni, ahonnan a kliens letöltheti azokat. Ha az egész "3d világ adatbázist" akarod RMI-n keresztül átadni, ott lehet hogy baj van egy kicsit a koncepcióval.
  4. Unknown User (frimen)

    Meddig menjek el, az Object-ig???? :(
    Nem az kevés.. ird ujra a JVM-et, jobban jársz!:)
    Ugyanez a helyzet áll elő, mikor az adatbázist akarom átadni.
    Szerintem probáld meg az egész számitógépet kiegésziteni a Serializable interfésszel és add át azt! Mi a fenének pitizel adatbázis, meg Java3D átatdással! :-)

    Fri
  5. Unknown User (kedzol)

    Egy picit mesélhetnél a projektedről, hátha jobban el tudunk igazodni a poblémádban... :)
    A szerver futtatja a MainScene-t, ami létrehozza a világot:
    import javax.media.j3d.*;
    import javax.vecmath.*;
    import java.awt.GraphicsConfiguration;
    import com.sun.j3d.utils.universe.SimpleUniverse;
    import java.io.Serializable;
    
    public class MainScene implements Serializable
    {
      private GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
      public Canvas3D canvas = new Canvas3D(config);
      public VirtualUniverse universe = new VirtualUniverse();
      public Locale locale = new Locale(universe);
      public BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 1000);
      public BranchGroup sceneRoot = null;
      public TransformGroup transRoot = new TransformGroup();
      public MainScene mainScene = null;
      public myKeyNavigatorBehavior keyNavBehavior = new myKeyNavigatorBehavior(0.25f, 5.0d);
      public UniverseBuilder universeBuilder = new  UniverseBuilder(locale, canvas, bounds);
      public TransformGroup model_Sky = null;
      public TransformGroup model_Landscape = null;
      public TransformGroup model_Tobias = null; 
      public TransformGroup model_Hordo_Fe01 = null;
      public TransformGroup model_Hordo_Fe02 = null;
      public TransformGroup model_Hordo_Fe03 = null;
      public TransformGroup model_Hordo_Fe04 = null;
      public TransformGroup model_Hordo_Fe05 = null;
      public TransformGroup model_Avatar = null;
      public TransformGroup model_Meat = null;
      public TransformGroup model_Tree_Platan = null;
      public TransformGroup model_Jeep = null;
      public TransformGroup model_Tree_Acer = null;
      public BranchGroup mainSceneBG = new BranchGroup();
      public BranchGroup meatBranchGroup = new BranchGroup();
    
      public MainScene()
      {
             mainSceneBG.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
             mainSceneBG.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
             mainSceneBG.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
             mainSceneBG.setCapability(BranchGroup.ALLOW_DETACH);
             mainSceneBG.setCapability(BranchGroup.ALLOW_PICKABLE_READ);
             mainSceneBG.setCapability(BranchGroup.ENABLE_PICK_REPORTING);
             meatBranchGroup.setCapability(BranchGroup.ALLOW_DETACH);
             meatBranchGroup.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
             meatBranchGroup.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
             canvas.setSize(790, 440);
             sceneRoot = createSceneGraph();
             universeBuilder.addkeyNavBehavior(keyNavBehavior);
             locale.addBranchGraph(universeBuilder.viewPlatformBRANCHGROUP);
             locale.addBranchGraph(sceneRoot);
      }
    
    // [...]
    
      public BranchGroup createSceneGraph()
      {
        Color3f lColor1 = new Color3f(0.3f, 0.3f, 0.3f);
        Vector3f lDir1 = new Vector3f( -0.2f, -0.2f, -0.2f);
        Color3f alColor = new Color3f(0.5f, 0.5f, 0.5f);
        AmbientLight aLgt = new AmbientLight(alColor);
        aLgt.setInfluencingBounds(bounds);
        DirectionalLight lgt1 = new DirectionalLight(lColor1, lDir1);
        lgt1.setInfluencingBounds(bounds);
        BranchGroup branchGroup = new BranchGroup();
        branchGroup.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
        branchGroup.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
        branchGroup.addChild(aLgt);
        branchGroup.addChild(lgt1);
        transRoot.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        createModels();
        branchGroup.addChild(transRoot);
        return branchGroup;
      }
    }
  6. Unknown User (kedzol)

    Hát nem tudom, mit nyomhattam meg... de nagyon gyorsan történt :))

    szóval:
    Canvas3D amire rajzolunk
    Locale a színtérgráf gyökere. Erre láncolunk fel mindent: transzformációk, modellek, fények...
    Úgy gondoltam, hogy a szerveren folyamatosan fut, várja a jelentkezőket. ezen kívül még fut rajta az adb aztán slussz. A kliens hozza létre az ablakokat (Main, Karakter, Help stb.), és meg kell tudni hívnia legalább a vásznat és a locale-t, hogy megjeleníthesse, de hát ezek valóban nem serializalhatóak...
    Remélem így már érthetőbb egy kicsit a probléma, vagy előbukkanhat egy megoldás. Ha valami van írjatok!
    Z
  7. Hmm... én erőteljes koncepcionális hibát vélek felfedezni. Úgy is mondhatnám, hogy tapasztalatlanságot.

    Meg kellene ismerned és használnod kellene az MVC filozófiát, mert itt eléggé nagy kavarodás van, ahogy látom... :)

    Kell egy (vagy több) View. Ez az, amit a felhasználó lát, vagyis ennek és csakis itt és csakis ennek kell lennie a Java3D osztályoknak. Ez lehet egy applet, amelyet a böngésző futtat, vagy lehet akár egy alkalmazás is. Minden megjelenés itt történik.

    Kell egy és csakis egy Model. Ez az, ahol a megjelenítendő adatokat és a (később leírt) vezérléshez szükséges ismereteket tároljuk. Célszerűen egy adatbázis, vagy bármilyen perzisztens tároló.

    Kell minden View mögé egy Control. Ennek a dolga, hogy a View által mutatottakat szinkronban tartsa a Model tartalmával. Ha a Model változik, a Control aktuálizálja a megjelenítést, ha pedig a megjelenítésen keresztük jön egy parancs, akkor azt végrehajtja a tárolt adatokon.

    A Java ezen az MVC modellen alapul, a Swing teljesen (utálják is sokan ezért... :), és a Java3D is ezen keresztül kezelendő. :)

    A lényeg, hogy ez rajtad így nem segít... mikor kell leadnod a szakdogát? Mert addigra gatyába kellene rázni ugye... :)
  8. Unknown User (kedzol)

    Hali

    Hát valóban tapasztalatlan vagyok, 3 félév Java után nem is olyan nagy csoda. Hallottam az MVC-ről de csak érintőlegesen szóltak róla, kb annyit, mint te itt. Avass be légyszives, honnan látod egy osztályt megnézve, hogy kavarodás van? Ha téma nem is segít a helyzet megoldásában szívesen elsajátítanám az MVC modellt, ugyhogy ha van valami jó anyagod küld el kérlek.

    Visszatérve a felvetett problémára: A gond az, hogy az RMI-vel átvivendő objektumok nem serializálhatóak. Megpróbálkoztam a Canvas3D osztállyal is, a dokumentációban ez áll:
     Class Canvas3D
    java.lang.Object
    |
    +--java.awt.Component
    |
    +--java.awt.Canvas
    |
    +--javax.media.j3d.Canvas3D
    All Implemented Interfaces:
    javax.accessibility.Accessible, java.awt.image.ImageObserver, java.awt.MenuContainer, java.io.Serializable
    mégis a következő hibaüzenetet kapom:
    java.lang.UnsupportedOperationException: Canvas3D does not support serialization
    mi a véleményed?

    A leadási határidő egyébbként jövő hét hétfő! Kicsit szorít az idő. Igaz, hogy már csak ezt kell megoldani, a többi funkció okés.

    üdv Zoli
  9. Hát valóban tapasztalatlan vagyok, 3 félév Java után nem is olyan nagy csoda. Hallottam az MVC-ről de csak érintőlegesen szóltak róla, kb annyit, mint te itt. Avass be légyszives, honnan látod egy osztályt megnézve, hogy kavarodás van?
    Nem látom igazán, csak eléggé furcsa, hogy RMI-vel oldanál meg egy ilyen problémát. Az MVC-t kissé nehéz elmagyarázni, hosszadalmasan meg nincs időm jelenleg... :(
    Ha téma nem is segít a helyzet megoldásában szívesen elsajátítanám az MVC modellt, ugyhogy ha van valami jó anyagod küld el kérlek.
    Szerintem 6 nap alatt nem tudod úgy átstruktúrálni a programod szerkezetét, hogy MVC szerint dolgozzon, hiszen a program modellje helyett egy alapvetően View célú osztálykönyvtárad van (a Java3D).
    java.lang.UnsupportedOperationException: Canvas3D does not support serialization
    Önmaga az, de lehet, hogy benne lévő egyéb kapcsolatok már nem azok... Egy Canvas3D-t eléggé esélytelen áthúzni hálózaton, hiszen rajta csüng egy teljes J3D univerzum, amelyeket nem tud az RMI átvinni, mert nem feladata. Ha a másik oldalon egy ilyen Canvas3D-t deserializálnál, akkor egy csomó belső metódusa lógna a levegőben, mert meghívnának olyan példányok metódusait, amelyeket az RMI nem tudott áthúzni (szerintem nem is képes rekurzíve osztályt szerializálni, de javítson ki valaki).
    A leadási határidő egyébbként jövő hét hétfő! Kicsit szorít az idő. Igaz, hogy már csak ezt kell megoldani, a többi funkció okés.
    Akkor erre kellene koncentrálni.

    Nézzük előlről. Van a programodnak egy olyan része, amely létrehoz egy J3D univerzumot, annak gyökerét (a Canvas3D-t) vagy részeit RMI-vel elérhetővé teszi, majd a kliens gyakorlatilag egy üres panel, amire kitennéd az RMI-vel áthúzott Canvas3D-t.

    Ha így van, akkor ez esélytelen. A J3D Canvas3D példánya folyamatosan billentyűzet és egér eseményeket akar küldeni a szerver felé (de nem tud, mert az RMI erre nem jó), és folyamatosan kérdezi az alatta lévő univerzumot, hogy a benne lévő tárgyakat ábrázolni tudja (de nem tudja kérdezni, mert nincs folyamatos RMI kapcsolat).

    Valahogy másképp kellene megoldani... az RMI olyan, mint a HTTP protokoll: indul egy kérés, a szerver erre ad egy választ. De nincs állandó kapcsolat. HTTP sem tud olyan dolgokat, amik állandó kapcsolatot igényelnek, folyamatos a kérdés-válasz mind-mind új HTTP kérést jelent.

    A kérdés az, hogy mi a szakdolgozat vállalt témája, és mennyire lehet a kész kódot átforgatni olyanná, hogy ez kivitelezhető legyen.
  10. RMI-vel egész jól meg lehet csinálni az MVC mintát.

    A szerveren van a modell. A szerver tartalmazza egy adatbázisban, vagy ő számolja ki szimulációval hogy mi hol van a térben, de fogalma sincs, hogy hogyan kell kirajzolni. Tehát a szerveren (a modellben) egyáltalán nincsenek a megjelenítéssel foglalkozó kódrészek, hiszen a modell nem tudja, hogy hogyan fogják megjeleníteni. Ilyet hogy Canvas, le sem szabad írni a szerveren, sehol. Egy modellt meg lehet jeleníteni sokféleképpen (többféle 3d mtor, vagy akár paraméteres megjelenítés), az MVC lényege, hogy ezt leválassza a modellről. A modellnek vannak olyan lekérdező metódusai, amik a modell pillanatnyi állapotát vagy részállapotát tudják visszaadni. Pl. List getNearbyObjects(double x, double y, double z) - visszaadja a közeli objektumokat. Fontos még, hogy ne legyen túl sok vagy túl bonyolult lekérdező metódus. Maga a modell állhat rengeteg osztályból és lehet tetszőlegesen bonyolult, de legyen egy egyszerű, kevés metódust tartalmazó osztály benne, amin az aktuális állapotát le lehet kérdezni. (Ez a facade/homlokzat minta.) Ez  a felület fog megjelenni a távoli elérésre szánt osztályban, ami a szerver elérési pontja.

    A kliensen van a view (nézet). A view tartalmazza a megjelenítő logikát, de hogy konkrétan mit jelenít meg (magukat az adatokat) azt teljes egészében a modellből veszi.  Szóval a view hívogatja a modell getNearbyObjects() metódusát és kirajzolja szépen a saját canvas-ára a visszaadott dolgokat. Ebből adódik, hogy a View alatt pedig lecserélhető a modell, de ez most mellékes. Nagyjából a kliensen van az egész 3d java csomag.

    A Controller is mellékes most.

    Ebben az esetben a view és a modell között RMI kapcsolat van. A kapcsolaton csak egyszerű adatok vándorolnak, amik a modell állapotát reprezentálják. (Ezeket hívják transzfer objektumnak.) Ilyesmik, hogy 0,0,0 koordinátán van egy fa, 10,  4, 6 koordinátán van egy autó, az ég textúrája (bitmap). Ezeknek kompakt és Serializable objektumoknak kell lenniük. A kompakt azt jelenti, hogy nem kapcsolódnak semmihez, magukban értelmesek, minden szükséges adatot tartalmaznak amit át kell vinni a hálózaton. Pl. az nem jó, hogy egy transzfer objektum egy fájlnevet tartalmaz, mert a fájlnevet hiába viszed át a hálózaton, a szerver és a kliens gépen nem ugyanaz a fájlrendszer. Ilyen esetekben a fájl konkrét tartalmát kell tartalmaznia a transzfer objektumnak.

    Tehát a lényeg a modell és a view szétválasztása, egyszerű transzfer objektumok  és egyszerű facade felület a modellen.
  11. Még egy kis kiegészítés:

    Ha járatos vagy az RMI alapjaiban, tudod hogy kell definiálni egy távoli interfészt, amit a távoli elérésre szánt objektumnak (a szervernek) implementálnia kell. A kliens pedig ezt az interfészt hívogatja, az RMI rendszer pedig gondoskodik róla, hogy a hívások átmenjenek a hálózaton.

    Talán nem túl meglepő módon, a modell homlokzata, amit említettem hogy egyszerű kell hogy legyen, pont alkalmas ilyen távoli interfésznek. Például:
    public interface MyWorldInterface extends Remote {
        public List getNearbyObjects(double, double, double) throws RemoteException
    }
    Szóval az MVC minta pont szépen beleillik az RMI koncepciójába.
  12. Szóval az MVC minta pont szépen beleillik az RMI koncepciójába.
    Azt hiszem ezen a ponton félreérthető volt, amit írtam, nem az RMI-t nem az MVC viszonylatában gondoltam problémásnak (hiszen ezt meg lehet oldani RMI-ven, SOAP-al, HTTP-n, JSON-al, stb-vel), hanem a J3D, mint távoli oldal viszonylatában.
  13. Én is pont ezt tartom problémásnak. Nem ismerem a J3D-t, nem tudom hogy ezek a TransformGroup-ok és egyéb group-ok (minden  canvas és a config kivételével), amik úgy látom a modell elemeit tartalmazzák alkalmasak-e transzfer objektumoknak. Ha implementálják a Serializable-t akkor valószínűleg alkalmasak. Ha nem akkor programozni kell...
  14. Csak, hogy en is beleszoljak (most mar nem birom ki)... :)

    Harom dolog fog kelleni:
    1. szerver oldalra olyan osztalyok, amelyeket te keszitesz, es szerializalhatoak (adattagjaikkal es az egymashoz valo kapcsolataikkal leirjak a teljes vilagot - anelkul, hogy a megjelenites modjaval tenylegesen foglalkoznal)
    2. szerver oldalra olyan osztalyok, amelyek RMI-interfeszeket valositanak meg, es az 1. pontban leirt osztalyokbol szarmazo objektumokat lehet veluk (metodusaikkal) tologatni fel-le (nyilvan kliens oldalra is kellenek osztalyok, amik ezeket hivogatjak, de ez most nem is volt kerdeses)
    3. kliens oldalra mehet a teljes Java3D, de azt meg kell oldanod valahogy, hogy az altalad letrehozott objektumok (1. pont) alapjan Java3D objektumokat hozz letre

    Igyekeztem tomor, es vilagos lenni, remelem sikerult :)
  15. Abszolút megoldható RMI-vel, de a változókat nem lehet elérni, csak metódusokat lehet hívni. Változókat getter metódusokkal tudod elérni. Lehet hogy úgy is jó ahogy te próbálod, én így szoktam szervert csinálni (rmiregistry programot nem kell kézzel elindítani):

    AlarmServerImpl server = new AlarmServerImpl("AlarmServer");
    Registry reg = LocateRegistry.createRegistry(1099);
    reg.bind("AlarmServer", server);

    Az 1.5-ös verziótól (ha a kliens és a szerver is 1.5 vagy késpbbi) már nem kell használni az rmic-t, mert a csonk osztályokat dinamikusan generálja futási időben.