Spring + 2X

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

Moderators: Lapo, Bax

Gnat
Posts: 2
Joined: 29 Nov 2010, 07:13

Spring + 2X

Postby Gnat » 29 Nov 2010, 07:34

I have the project working on sfs 1.6 with spring framework on server-side.
Now I want to move it on 2X version. Unfortunately I have the problem with classpath:
"org.springframework.beans.factory.NoSuchBeanDefinitionException"
I just put all my java-classes into .jar file and create new extension for it.
"spring-config.xml" there is in kernel folder.

Thanks for help!
User avatar
Lapo
Site Admin
Posts: 23026
Joined: 21 Mar 2005, 09:50
Location: Italy

Postby Lapo » 29 Nov 2010, 09:58

I would suggest to put Spring in the main lib/ folder of the server together with your config file. In case it's not seen anyways move the config file in the main SFS2X folder, side by sude with the launcher script
Lapo
--
gotoAndPlay()
...addicted to flash games
Gnat
Posts: 2
Joined: 29 Nov 2010, 07:13

Postby Gnat » 30 Nov 2010, 15:32

Lapo, unfortunately it didn't help. I have the same problem :(
User avatar
Lapo
Site Admin
Posts: 23026
Joined: 21 Mar 2005, 09:50
Location: Italy

Postby Lapo » 30 Nov 2010, 17:11

Not even by putting the file under the main SFS2X folder?
In that case you might need to edit the classpath to make sure the file is found, anyways you should explain a little bit better what the spring libraries consist of and what other resources/config files are necessary.

thanks
Lapo

--

gotoAndPlay()

...addicted to flash games
drh_qtm
Posts: 40
Joined: 15 Apr 2010, 09:07

Spring SFS2

Postby drh_qtm » 22 Dec 2010, 09:28

Hi Does anyone have an example if this working? I'm pretty new to Spring but based on my current understanding an ApplicationContext needs to be constructed in order to load in the spring configuration from an external xml file in order to get Spring working generally but I was wondering how to do this with SFS2X?

I have tried by placing the following code in the init method of one of my extensions where applicationContext.xml is my spring config file and is on the class path (I have put it in the SFS2X dir, the SFS2x/lib dir and a few other places.

Code: Select all

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");


Whenever I try to launch he server with this code in the extension I get the error shown below where it seems to attempt to do something but then the boot process stops and the server does not start. I'm probably doing something totally incorrect but would really appreciate if anyone had any ideas how I could get Spring working wuth SFS2x

21 Dec 2010 09:15:09,551 INFO [main] entities.managers.SFSZoneManager - Creating room: (default) Limbo
21 Dec 2010 09:15:09,557 WARN [main] entities.managers.SFSZoneManager - RoomSetting literal not found:
21 Dec 2010 09:15:09,560 INFO [main] v2.api.SFSApi - Room created: [ Room: Limbo, Id: 0, Group: default, isGame: false ]
21 Dec 2010 09:15:09,560 INFO [main] entities.managers.SFSZoneManager - Creating room: (default) User
21 Dec 2010 09:15:09,561 WARN [main] entities.managers.SFSZoneManager - RoomSetting literal not found:
21 Dec 2010 09:15:09,561 INFO [main] v2.api.SFSApi - Room created: [ Room: User, Id: 1, Group: default, isGame: false ]
21 Dec 2010 09:15:09,573 DEBUG [main] user.room.UserRoomExtension - Initialised!
21 Dec 2010 09:15:09,583 DEBUG [main] user.buddylist.BuddyListPersister - BuddyListPersister initialized.
21 Dec 2010 09:15:09,586 DEBUG [main] secure.zone.SecureZoneExtension - initialise SecureZoneExtension
21 Dec 2010 09:15:09,618 INFO [main] context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@451ef443: startup date [Tue Dec 21 09:15:09 GMT 2010]; root of context hierarchy
21 Dec 2010 09:15:09,649 INFO [Thread-2] entities.managers.SFSZoneManager - BuddyList saveAll...
21 Dec 2010 09:15:09,649 WARN [SFS2X ShutdownHook] v2.core.SFSShutdownHook - SFS2X is shutting down. The process may take a few seconds...
21 Dec 2010 09:15:09,671 INFO [Thread-3] entities.managers.SFSBannedUserManager - BanUser data saved.
User avatar
Lapo
Site Admin
Posts: 23026
Joined: 21 Mar 2005, 09:50
Location: Italy

Postby Lapo » 22 Dec 2010, 09:42

Seems like something (Spring?) is quitting the application :(
In fact the last two log messages are exactly the SFS2X Shutdown hook running, right before the JVM is tore down.

I am no Spring expert but I guess there should be some Spring logs somewhere showing some more details.

Final note: the xml config file should go in the SFS2X root folder, the lib/ folder is not exactly in the classpath. Only the jar files contained in it are. (because we use the Java6 wildcard notation)
Lapo

--

gotoAndPlay()

...addicted to flash games
drh_qtm
Posts: 40
Joined: 15 Apr 2010, 09:07

Postby drh_qtm » 22 Dec 2010, 10:19

Thanks Marco, got my best man looking at it. :wink: We will post here once we figure out how to set it all up for others benefit
silvertip
Posts: 7
Joined: 18 Dec 2010, 15:32

Postby silvertip » 30 Jan 2011, 08:52

Hi drh_qth,

Did you manage to resolve your issue? We may be using Spring with Smartfox 2x.

Thanks,
Silvertip.
drh_qtm
Posts: 40
Joined: 15 Apr 2010, 09:07

Postby drh_qtm » 02 Feb 2011, 07:21

Hi Silvertip

I've managed to get SFS working with Spring, although I'm not sure if our approach will satisfy your requirements, I can run you through it in case it helps.

Firstly we have our project split into Business Logic Modules and Extensions, a BLM may be used by multiple extensions and as a result resides in the extensions/__lib__ and as you know extension have their own directory e.g. extensions/myExtension. The reason for separating out the business logic is two fold. Firstly it means that the core application is insulated from any changes in smartfox (e.g. when we go from SFS2 to SFS3 for example business logic modules don't care, the only changes will be in the extensions). Secondly in order to get Spring to work I have found that you need to have your jars in the __lib__ directory due to the way the classpath works in SFS.

You will be able to see this if you add a line to the log4j.properties file to trace out the spring debug (log4j.category.org.springframework=DEBUG,consoleAppender,fileAppender) when you try and load your applicationContext file. What this means is that classes in the extension/myExtension jar are not able to use spring instrumentation via annotations such as @Autowired as they never get scanned when the applicationContext loads. They way I have the extensions using the Business Logic modules is to have a singleton that performs the initialisation of the applicationContext upon created and then provides a couple of utility methods to allow the extensions to get at the beans. I have found this works well but I'm open to suggestions if anyone has found a better way to do this. So as way of an example I have something like this in a common project that all extensions can access:


Code: Select all

private static ContextUtil instance = new ContextUtil();
   Logger log = Logger.getLogger(this.getClass());
   
   private ApplicationContext context;
   
   private ContextUtil(){
      log.debug("Loading ContextUtil");
      try{
         context = new FileSystemXmlApplicationContext(new String[] {"config/applicationContext.xml"}, true);
      }catch(Exception e){
         log.error("Exception in context util",e);
      }
   }
   public static ContextUtil instance(){
      return instance;
   }
   
   public Object getService(String serviceName){
      return context.getBean(serviceName);
   }


Then I have let's say an extension to allow users to manage their account, with a request handler which handles requests to update their account details which would look something like:

Code: Select all

//get a reference to the application context utility singleton
ContextUtil contextUtil = ContextUtil.instance();
//get a reference to  my service implementation
IUserService userService = IUserService)contextUtil.getService(USER_SERVICE);

@Override
public void handleClientRequest(User user, ISFSObject params) {
      ISFSObject response = SFSObject.newInstance();
      //delegate to the service to do the update
      try{
         userService.updateUserDetails([get the relevant params from the params object]);
         response.putShort(Constants.RESPONSE_PARAMETER, RESPONSE_OK);
      }catch(Exception se){
         log.error("Solidifcation Exception",se);
         response.putShort(Constants.RESPONSE_PARAMETER, Constants.RESPONSE_ERROR);
      }
      send(ACCOUNT_UPDATE,response,user);
   }



All the extension handler does is extract the details the user is sending from the params object then delgates it off to the service to do the actual business logic work, writing to the db, etc. The UserService business logic module would look something like:


Code: Select all

private Logger log = Logger.getLogger(this.getClass());
   @Autowired
   private IUserDao userDao;

public void updateUserDetails(UserDetails userDetails){
  validateUserDetails(userDetails);
  //do any other BLogic
  //svae to the database 
  userDao.save(userDetails);
}



This approach might not suite what you are trying to do and there may be a better way but that's what I had to do to get it working. Hope it helps!
User avatar
levancho
Posts: 71
Joined: 27 Jun 2011, 16:03

Postby levancho » 31 Aug 2011, 15:57

small improvement suggestion, if you change getService method with generics, you do not have to cast returned object

for example:

Code: Select all

public  <T> T getService(Class<T> serviceClass){
          return context.getBean(serviceClass);
       }


or

Code: Select all

public  <T> T getService(String serviceName,Class<T> serviceClass){
          return context.getBean(serviceName,serviceClass );
       }
harlanji
Posts: 8
Joined: 15 Sep 2011, 01:50

Postby harlanji » 15 Sep 2011, 02:02

I realize this is an old thread, but to help future generations, this code works for me:


Code: Select all

       
ClassLoader origLoader = Thread.currentThread().getContextClassLoader();
ClassLoader extensionLoader = getClass().getClassLoader();

Thread.currentThread().setContextClassLoader(extensionLoader);

context = new GenericXmlApplicationContext(new ClassPathResource("/META-INF/spring/MyExtension-context.xml", extensionLoader));

Thread.currentThread().setContextClassLoader(origLoader);


All jars are deployed to the myExtension/ directory, and the spring configuration is in my extension's jar.
chenjie19891104
Posts: 34
Joined: 06 Feb 2012, 09:12

Postby chenjie19891104 » 07 Feb 2012, 10:12

harlanji wrote:I realize this is an old thread, but to help future generations, this code works for me:


Code: Select all

       
ClassLoader origLoader = Thread.currentThread().getContextClassLoader();
ClassLoader extensionLoader = getClass().getClassLoader();

Thread.currentThread().setContextClassLoader(extensionLoader);

context = new GenericXmlApplicationContext(new ClassPathResource("/META-INF/spring/MyExtension-context.xml", extensionLoader));

Thread.currentThread().setContextClassLoader(origLoader);


All jars are deployed to the myExtension/ directory, and the spring configuration is in my extension's jar.


Thank you for your answer,this method works fine.

But notice that when export your project to jar file using eclipse,make sure select the "Add directory entries",otherwise the annotations and bean definitions will not be scanned when the context is initialized!

Now I have integrate spring+hibernate+sfs2x, and all work fine!
harlanji
Posts: 8
Joined: 15 Sep 2011, 01:50

Postby harlanji » 08 Feb 2012, 00:27

Hey chenjie19891104:

I have since changed this to have the following code:

Code: Select all

    private void initSpringContext() {
        context = new GenericXmlApplicationContext();
        context.setClassLoader(ServiceAdapter.class.getClassLoader());
        context.load("classpath:/META-INF/spring/service-context.xml");
        context.refresh();
        context.getAutowireCapableBeanFactory().autowireBean(this);
    }


I think this is more elegant because we don't have to mess with the context class loader. ServiceAdapter is just a class in the same .jar as my extension, and I could have easily have used MyExtension.class.

The last line just makes Spring wire up my ServiceAdapter class (could easily be extension also).

Cheers.

Return to “SFS2X Questions”

Who is online

Users browsing this forum: Baidu [Spider], Stevenor and 114 guests