Classloading in web app

Post here your questions about SFS2X. Here we discuss all server-side matters. For client API questions see the dedicated forums.

Moderators: Lapo, Bax

User avatar
aakture
Posts: 23
Joined: 05 Jun 2012, 18:46

Classloading in web app

Postby aakture » 06 Nov 2012, 01:58

Similar to this issue: http://www.smartfoxserver.com/forums/viewtopic.php?f=18&t=15091&p=64437#p64437, I have web app, and in the web app rest services, when I try to access some extension code, I get ClassCastExceptions for classes that exist in the extension jar file. If I use the parent classes that exists in a jar that exists in the __lib__ directory, this seem to work ok. For example, I have a GameRoom class in a jar that exists in __lib__, and this code is fine:

Code: Select all

   public ServerRoomsResponse handleGetRoomsInfo() throws Exception
   {
      log.debug("handleGetRoomsInfo");
      ServerRoomsResponse serverRoomsResponse = new ServerRoomsResponse();
      List<ServerRoomsResponse.RoomInfo> roomInfoList = new ArrayList<ServerRoomsResponse.RoomInfo>();
      Zone gelatoZone = zoneManager.getZoneByName("Gelato");
      SFSExtension zoneExtension = (SFSExtension) gelatoZone.getExtension();
      try
      {
         @SuppressWarnings("unchecked")
         Collection<GameRoom> gameRooms = (Collection<GameRoom>) zoneExtension.handleInternalMessage(
               MessageName.SERVER_ROOM_INFO, new SFSObject());
         
         
         for (GameRoom
               gameRoom : gameRooms)
         {
            ServerRoomsResponse.RoomInfo roomInfo = new ServerRoomsResponse.RoomInfo();
            roomInfo.setRoomName(gameRoom.getRoomName());
            roomInfo.setPlayerCount(gameRoom.getPlayerCount());
            roomInfo.setUserCount(gameRoom.getUserCount());
            roomInfo.setSpectatorCount(gameRoom.getSpectatorCount());
            roomInfoList.add(roomInfo);
         }
      } catch (Exception ex)
      {
         log.error("Error in handleRoomInfo", ex);
         throw new Exception("Error in handleRoomInfo", ex);
      }
      serverRoomsResponse.setRooms(roomInfoList);
      return serverRoomsResponse;
   }


but, if I use a subclass of GameRoom, that exits in my extension jar (which is in an extension folder, not the __lib__ directory), I get a ClassCastException due to different class loaders:

Code: Select all

16:04:06.365 [154655349@qtp-1426481592-7] ERROR o.b.g.messages.SFSMessageHandler - Error in handleRoomInfo
java.lang.ClassCastException: org.buffalo.gelato.entities.GelatoRoom cannot be cast to org.buffalo.gelato.entities.GelatoRoom
   at org.buffalo.gelato.messages.SFSMessageHandler.handleGetRoomsInfo(SFSMessageHandler.java:97) [classes/:na]
   at org.buffalo.gelato.resources.ServerDataResource.getRoomData(ServerDataResource.java:22) [classes/:na]
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [na:1.7.0_04]
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [na:1.7.0_04]
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [na:1.7.0_04]
   at java.lang.reflect.Method.invoke(Method.java:601) [na:1.7.0_04]
   at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60) [jersey-bundle-1.13.jar:1.13]
   at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$TypeOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:185) [jersey-bundle-1.13.jar:1.13]


Is there a strategy I should use to be dealing with this issue? I've tried excluding my extension classes from the webapp (using provided scope in our pom) but that results in a java.lang.ClassNotFoundException.
User avatar
Lapo
Site Admin
Posts: 23027
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Classloading in web app

Postby Lapo » 06 Nov 2012, 07:59

By default SFS2X loads each Extenstion in a separate ClassLoader so Jetty won't be able to see those classes, because it has no clue of those ClassLoaders.

The most simple way to solve this is to deploy all game code to the __lib__/ folder, this way it will be "seen" both by the Server and the embedded Jetty.
There's however a downside, which is the fact that you won't be able to hot reload the Extensions at runtime, which is due to how ClassLoaders work in Java.

hope it helps
Lapo
--
gotoAndPlay()
...addicted to flash games
Satyarth
Posts: 131
Joined: 06 Nov 2008, 12:45
Location: Delhi, India
Contact:

Re: Classloading in web app

Postby Satyarth » 07 Nov 2012, 19:00

Lapo wrote:By default SFS2X loads each Extenstion in a separate ClassLoader so Jetty won't be able to see those classes, because it has no clue of those ClassLoaders.

The most simple way to solve this is to deploy all game code to the __lib__/ folder, this way it will be "seen" both by the Server and the embedded Jetty.
There's however a downside, which is the fact that you won't be able to hot reload the Extensions at runtime, which is due to how ClassLoaders work in Java.

hope it helps


Hi Lapo,

Is this the only way to solve this ? From what i understand, i need to have my game extension code inside extensions/XYZ folder, right ? If i put my extension code inside extensions/__lib__, then i get error

Message: Extension boot error. The provided path is not a directory: extensions/XYZ

Do you propose i change my extension name to __lib__ ??

Is this intended or you guys are planning to fix it ? How else are we supposed to call Game Code from Jetty webservice ?
User avatar
Lapo
Site Admin
Posts: 23027
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Classloading in web app

Postby Lapo » 08 Nov 2012, 08:22

Here's what you need to do to deploy the Extension to the main class loader:

1- Copy your <ExensionName.jar> file to the extensions/__lib__/ folder
2- Edit your zones/<ZoneName.zone.xml> file, it should look like this:

Code: Select all

  <extension>
    <name>__lib__</name>
    <type>JAVA</type>
    <file>put.here.the.name.of.your.MainExtensionClass</file>
    <propertiesFile></propertiesFile>
    <reloadMode>AUTO</reloadMode>
  </extension>


Also please keep in mind that by deploying the Extension in the top class loader you will not be able to hot-redeploy the extension during runtime. It will require a full restart.

Thanks
Lapo

--

gotoAndPlay()

...addicted to flash games
Satyarth
Posts: 131
Joined: 06 Nov 2008, 12:45
Location: Delhi, India
Contact:

Re: Classloading in web app

Postby Satyarth » 08 Nov 2012, 17:14

Yes i did exactly the same and it does not work, SFS still looks for the folder inside extensions with the same name as the ZoneName

I get this error :

Message: Extension boot error. The provided path is not a directory: extensions/XYZ
User avatar
Lapo
Site Admin
Posts: 23027
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Classloading in web app

Postby Lapo » 08 Nov 2012, 17:57

I think you edited the wrong part of the XML file.
Make double sure that the block of XML is not part of a Room definition, otherwise you're setting the Extension for a Room not for the Zone. They all look the same but the block of XML you are looking for should be the very last in the file, and it's not part of any <Room..></Room> definition.

Thanks
Lapo

--

gotoAndPlay()

...addicted to flash games
Satyarth
Posts: 131
Joined: 06 Nov 2008, 12:45
Location: Delhi, India
Contact:

Re: Classloading in web app

Postby Satyarth » 09 Nov 2012, 01:20

I am doing what you are saying and I get the error. I did do the changes outside <rooms/> Please take a look at my zone config file :



<zone>
<name>AwesomeGame</name>
<isCustomLogin>true</isCustomLogin>
<isForceLogout>true</isForceLogout>


............................................

<extension>
<name>__lib__</name>
<type>JAVA</type>
<file>org.buffalo.bingoblitz.extensions.BingoBlitzZoneExtension</file>
<propertiesFile></propertiesFile>
<reloadMode>AUTO</reloadMode>
</extension>
<buddyList active="false">
<allowOfflineBuddyVariables>true</allowOfflineBuddyVariables>
<maxItemsPerList>100</maxItemsPerList>
<maxBuddyVariables>15</maxBuddyVariables>
<offlineBuddyVariablesCacheSize>500</offlineBuddyVariablesCacheSize>
<customStorageClass></customStorageClass>
<useTempBuddies>true</useTempBuddies>
<buddyStates class="java.util.Arrays$ArrayList">
<a class="string-array">
<string>Available</string>
<string>Away</string>
<string>Occupied</string>
</a>
</buddyStates>
<badWordsFilter isActive="false"/>
</buddyList>
<databaseManager active="false">
<driverName></driverName>
<connectionString></connectionString>
<userName></userName>
<password></password>
<testSql></testSql>
<maxActiveConnections>10</maxActiveConnections>
<maxIdleConnections>10</maxIdleConnections>
<exhaustedPoolAction>FAIL</exhaustedPoolAction>
<blockTime>3000</blockTime>
</databaseManager>
</zone>
User avatar
Lapo
Site Admin
Posts: 23027
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Classloading in web app

Postby Lapo » 09 Nov 2012, 07:47

Thanks. Can you please report the stack trace of the exception?
Also, it goes without saying, it is necessary to deploy the jar file containing your classes in the __lib__ folder.
Lapo

--

gotoAndPlay()

...addicted to flash games
User avatar
aakture
Posts: 23
Joined: 05 Jun 2012, 18:46

Re: Classloading in web app

Postby aakture » 09 Nov 2012, 18:56

Here's the trace. We have the extension jar and it's config.properties in the __lib__ directory, and have modified the zone config file as you described. Thanks.

Code: Select all

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Exception: com.smartfoxserver.v2.exceptions.SFSExtensionException
Message: Extension boot error. The provided path is not a directory: extensions/BingoBlitz
Description: Failure while creating room extension.
Possible Causes: If the CreateRoom request was sent from client make sure that the extension name matches the name of an existing extension
+--- --- ---+
Stack Trace:
+--- --- ---+
com.smartfoxserver.v2.entities.managers.SFSExtensionManager.createJavaExtension(SFSExtensionManager.java:345)
com.smartfoxserver.v2.entities.managers.SFSExtensionManager.createExtension(SFSExtensionManager.java:259)
com.smartfoxserver.v2.entities.managers.SFSRoomManager.createRoomExtension(SFSRoomManager.java:225)
com.smartfoxserver.v2.entities.managers.SFSRoomManager.createRoom(SFSRoomManager.java:171)
com.smartfoxserver.v2.entities.SFSZone.createRoom(SFSZone.java:232)
com.smartfoxserver.v2.api.SFSApi.createRoom(SFSApi.java:680)
org.buffalo.platform.entities.GameRoom.initSFSRoomExtension(GameRoom.java:373)
org.buffalo.platform.entities.GameRoom.<init>(GameRoom.java:166)
org.buffalo.bingoblitz.entities.BingoBlitzRoom.<init>(BingoBlitzRoom.java:68)
org.buffalo.bingoblitz.entities.BingoBlitzRoom$Builder.build(BingoBlitzRoom.java:215)
org.buffalo.bingoblitz.managers.BingoBlitzRoomsManager.createRoom(BingoBlitzRoomsManager.java:83)
org.buffalo.platform.managers.RoomsManager.initDefaultRooms(RoomsManager.java:82)
org.buffalo.bingoblitz.extensions.BingoBlitzZoneExtension.initCities(BingoBlitzZoneExtension.java:92)
org.buffalo.platform.extensions.GenericZoneExtension.init(GenericZoneExtension.java:52)
com.smartfoxserver.v2.entities.managers.SFSExtensionManager.createExtension(SFSExtensionManager.java:302)
com.smartfoxserver.v2.entities.managers.SFSZoneManager.createZone(SFSZoneManager.java:428)
com.smartfoxserver.v2.entities.managers.SFSZoneManager.initializeZones(SFSZoneManager.java:240)
com.smartfoxserver.v2.SmartFoxServer.start(SmartFoxServer.java:230)
com.smartfoxserver.v2.Main.main(Main.java:31)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:601)
com.exe4j.runtime.LauncherEngine.launch(Unknown Source)
com.install4j.runtime.launcher.Launcher.main(Unknown Source)
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
User avatar
Lapo
Site Admin
Posts: 23027
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Classloading in web app

Postby Lapo » 09 Nov 2012, 19:08

In my previous posts I gave directions to configure the Zone file in order to load the Zone extension but the error you're showing here is a different thing.

The server is complaining because you're creating a Room at runtime with an attached extension expected to be found under the extensions/BingoBlitz/ folder. This is presumably happening in the init() method.
So now we're talking either about a different extension that is missing or maybe you need to change the code so that it points to __lib__ again.

Not knowing what your code does makes it difficult to guess.

Thanks
Lapo

--

gotoAndPlay()

...addicted to flash games
Satyarth
Posts: 131
Joined: 06 Nov 2008, 12:45
Location: Delhi, India
Contact:

Re: Classloading in web app

Postby Satyarth » 09 Nov 2012, 19:25

Hey Lapo,

I think our problem is due to this :

We specified Zone extension folder to be __lib__ in config.xml But for RoomExtension how do we specify that it needs to be loaded from inside __lib__ ?

We do not have static rooms, we are creating rooms dynamically. Can we still somehow specify them in config file in SFS 2X ?
User avatar
Lapo
Site Admin
Posts: 23027
Joined: 21 Mar 2005, 09:50
Location: Italy

Re: Classloading in web app

Postby Lapo » 09 Nov 2012, 19:44

Same thing, you specify "__lib__" for the extension folder in the parameter passed via code (i.e. the RoomExtensionSettings class)
Lapo

--

gotoAndPlay()

...addicted to flash games
User avatar
aakture
Posts: 23
Joined: 05 Jun 2012, 18:46

Re: Classloading in web app

Postby aakture » 09 Nov 2012, 20:24

This seems to have solved it, thanks very much.

Return to “SFS2X Questions”

Who is online

Users browsing this forum: No registered users and 141 guests