package com.idega.business;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.ejb.CreateException;
import javax.ejb.RemoveException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import com.idega.idegaweb.IWApplicationContext;
import com.idega.idegaweb.IWUserContext;
import com.idega.repository.data.RefactorClassRegistry;
import com.idega.repository.data.Singleton;
import com.idega.util.reflect.MethodFinder;
/**
* IBOLookup is a class use to get instances of IBO (Service and Session) objects.<br><br>
* <br>Instances of IBOService classes are stored in the IWApplicationContext and obtained by passing a reference to the application context and either a class representing a bean interface of implementation.
* <br>Instances of IBOSession classes are stored in the IWUserContext and obtained by passing a reference to the user context and either a class representing a bean interface of implementation.
* Copyright (c) 2002-2004 Idega Software
* @author <a href="tryggvi@idega.is">Tryggvi Larusson</a>
*/
public class IBOLookup implements Singleton
{
private static IBOLookup instance;
protected static synchronized IBOLookup getInstance()
{
if (instance == null)
{
instance = new IBOLookup();
}
return instance;
}
/**
* Unload the previously loaded instance and all its resources
*/
public static void unload(){
instance=null;
}
protected final String HOME_SUFFIX = "Home";
protected final String FACTORY_SUFFIX = "HomeImpl";
private final String BEAN_SUFFIX = "Bean";
protected String getBeanSuffix()
{
return this.BEAN_SUFFIX;
}
private Map homes;
private Map beanClasses;
private Map interfaceClasses;
private Map services;
private Properties jndiProperties;
private Map createMethodsMap;
protected IBOLookup()
{}
protected static Object getHomeForClass(Class beanInterfaceClass) throws IBOLookupException
{
return getInstance().getEJBHomeInstance(beanInterfaceClass);
}
protected static IBOHome getIBOHomeForClass(Class beanInterfaceClass) throws IBOLookupException
{
return (IBOHome) getHomeForClass(beanInterfaceClass);
}
/**
* Returns an instance of a IBOSession bean.
* The instance is stored in the session for the (current) user context. After <b>this</b> method is called there should be a corresponding call to removeSessionAttribute() to clean up from the users context.
* @param iwuc A reference to the user (context) the bean instance is working under.
* @param beanInterfaceClass The bean (implementation or interface) class to be used. (For example UserBusiness.class or UserBusinessBean.class)
*/
public static IBOSession getSessionInstance(IWUserContext iwuc, Class beanInterfaceClass) throws IBOLookupException
{
return getInstance().getSessionInstanceImpl(iwuc, beanInterfaceClass);
}
private IBOSession getSessionInstanceImpl(IWUserContext iwuc, Class beanInterfaceClass) throws IBOLookupException
{
IBOSession session = (IBOSession) iwuc.getSessionAttribute(this.getSessionKeyForObject(beanInterfaceClass));
if (session == null)
{
try
{
session = instanciateSessionBean(beanInterfaceClass);
iwuc.setSessionAttribute(getSessionKeyForObject(beanInterfaceClass), session);
session.setUserContext(iwuc);
}
catch (CreateException cre)
{
throw new IBOLookupException("[IBOLookup] : CreateException : " + cre.getMessage());
}
catch (RemoteException cre)
{
throw new IBOLookupException("[IBOLookup] : RemoteException : " + cre.getMessage());
}
}
return session;
}
/**
* Cleans up after an an instance of a IBOSession bean has been used.
* @param iwuc A reference to the user (context) the bean instance is working under.
* @param beanInterfaceClass The bean (implementation or interface) class to be used. (For example UserBusiness.class or UserBusinessBean.class)
*/
public static void removeSessionInstance(IWUserContext iwuc, Class beanInterfaceClass)
throws RemoteException, RemoveException
{
getInstance().removeSessionInstanceImpl(iwuc, beanInterfaceClass);
}
private void removeSessionInstanceImpl(IWUserContext iwuc, Class beanInterfaceClass)
throws RemoteException, RemoveException
{
IBOSession session = getSessionInstance(iwuc, beanInterfaceClass);
session.remove();
iwuc.removeSessionAttribute(getSessionKeyForObject(beanInterfaceClass));
}
private IBOSession instanciateSessionBean(Class beanInterfaceClass) throws IBOLookupException, CreateException
{
return (IBOSession) instanciateServiceBean(beanInterfaceClass);
}
private IBOService instanciateServiceBean(Class beanInterfaceClass) throws IBOLookupException, CreateException
{
IBOService session = null;
IBOHome home = getIBOHomeForClass(beanInterfaceClass);
try{
Method defaultCreateMethod = getCreateMethod(home);
session = (IBOService)defaultCreateMethod.invoke(home,null);
}
catch(InvocationTargetException ite){
//ite.printStackTrace();
Throwable e = ite.getTargetException();
e.printStackTrace();
throw new CreateException("Exception invoking create method for: "+beanInterfaceClass.getName()+". Error was:"+e.getClass().getName()+":"+e.getMessage());
}
catch(Exception e){
e.printStackTrace();
throw new CreateException("Exception invoking create method for: "+beanInterfaceClass.getName()+". Error was:"+e.getMessage());
}
//session = home.createIBO();
return session;
}
/**
* Method getCreateMethod.
* @param home
* @return Method
*/
private Method getCreateMethod(IBOHome home) throws NoSuchMethodException{
Map map = getCreateMethodsMap();
Class homeClass = home.getClass();
Method m = (Method)map.get(homeClass);
if(m==null){
m = MethodFinder.getInstance().getMethodWithNameAndNoParameters(homeClass,"create");
map.put(homeClass,m);
}
return m;
}
/**
* Method getCreateMethodsMap.
* @return Map
*/
private Map getCreateMethodsMap() {
if(this.createMethodsMap==null){
this.createMethodsMap=new HashMap();
}
return this.createMethodsMap;
}
/**
* Returns an instance of a IBOService bean.
* The instance is stored in the application context and is shared between all users.
* @param iwac A reference to the application (context) the bean should be looked up.
* @param beanInterfaceClass The bean (implementation or interface) class to be used. (For example UserBusiness.class or UserBusinessBean.class)
*/
public static IBOService getServiceInstance(IWApplicationContext iwac, Class beanInterfaceClass)
throws IBOLookupException
{
return getInstance().getServiceInstanceImpl(iwac, beanInterfaceClass);
}
private IBOService getServiceInstanceImpl(IWApplicationContext iwac, Class beanInterfaceClass)
throws IBOLookupException
{
IBOService service = (IBOService) this.getServicesMap(iwac).get(beanInterfaceClass);
if (service == null)
{
try
{
service = this.instanciateServiceBean(beanInterfaceClass);
if(iwac!=null){
((IBOServiceBean) service).setIWApplicationContext(iwac);
}
service.initializeBean();
getServicesMap(iwac).put(beanInterfaceClass, service);
}
catch (CreateException cre)
{
throw new IBOLookupException("[IBOLookup] : CreateException : " + cre.getMessage());
}
}
return service;
}
protected Class getHomeInterfaceClassFor(Class entityInterfaceClass) throws Exception
{
try{
//First try to suffix the Home to the interface class name
String baseClassName = getInterfaceClassForNonStatic(entityInterfaceClass).getName();
String homeClassName = baseClassName + this.HOME_SUFFIX;
return RefactorClassRegistry.forName(homeClassName);
}
catch(ClassNotFoundException cnfe){
//If that doesn't work then try to suffix the Home to the bean implementation class name - the bean suffix
String beanClassName = getBeanClassForNonStatic(entityInterfaceClass).getName();
String baseClassName = beanClassName.substring(0,beanClassName.indexOf(getBeanSuffix()));
String homeClassName = baseClassName + this.HOME_SUFFIX;
return RefactorClassRegistry.forName(homeClassName);
}
}
protected Class getFactoryClassFor(Class entityInterfaceClass) throws Exception
{
try{
//First try to suffix the FACTORY_SUFFIX to the bean implementation class name - the bean suffix
String beanClassName = getBeanClassForNonStatic(entityInterfaceClass).getName();
String baseClassName = beanClassName.substring(0,beanClassName.indexOf(getBeanSuffix()));
String homeClassName = baseClassName + this.FACTORY_SUFFIX;
return RefactorClassRegistry.forName(homeClassName);
}
catch(ClassNotFoundException cnfe){
//If that doesn't work then try to suffix the FACTORY_SUFFIX to the interface class name
String baseClassName = getInterfaceClassForNonStatic(entityInterfaceClass).getName();
String homeClassName = baseClassName + this.FACTORY_SUFFIX;
return RefactorClassRegistry.forName(homeClassName);
}
}
private String getSessionKeyForObject(Class interfaceClass)
{
return "IBO." + interfaceClass.getName();
}
/**
* Gets an instance of the implementation of the Home interface for the data bean.
* <br>The object retured can then needs to be casted to the specific home interface for the bean.
* @param entityInterfaceClass i the interface of the data bean.
*/
protected Object getEJBHomeInstance(Class entityBeanOrInterfaceClass){
return getEJBHomeInstance(entityBeanOrInterfaceClass, null);
}
protected Object homesMapLookup(Class entityInterfaceClass, String parameter) {
return getHomesMap().get(entityInterfaceClass+parameter);
}
/**
* Gets an instance of the implementation of the Home interface for the data bean.
* <br>The object retured can then needs to be casted to the specific home interface for the bean.
* @param entityInterfaceClass i the interface of the data bean.
* @param parameter is a parameter used to separete different instances of the same Home class
*/
protected Object getEJBHomeInstance(Class entityBeanOrInterfaceClass, String parameter){
//Double check so it is not the bean class that is sent into the methods below
Class entityInterfaceClass = getInterfaceClassForNonStatic(entityBeanOrInterfaceClass);
//EJBHome home = (EJBHome) homes.get(entityInterfaceClass);
// Object home = getHomesMap().get(entityInterfaceClass+parameter);
Object home = homesMapLookup(entityInterfaceClass, parameter);
if (home == null)
{
try
{
if(doLookupOverJNDI(entityInterfaceClass)){
//home = (EJBHome) getHomeThroughJNDI(getInterfaceClassForNonStatic(entityInterfaceClass));
home = getHomeThroughJNDI(entityInterfaceClass);
}
else{
Class factoryClass = getFactoryClassFor(entityInterfaceClass);
home = factoryClass.newInstance();
}
getHomesMap().put(entityInterfaceClass+parameter, home);
}
catch (Exception e)
{
//e.printStackTrace();
throw new RuntimeException(
"Error initializing Home for EJB Bean Interface class:"
+ entityInterfaceClass.getName()
+ " - Message: "
+ e.getMessage());
}
}
return home;
}
/**
* Gets the Class object for the (BMP) bean class of a data bean.
* @param entityInterfaceClass i the (Remote) interface of the data bean.
*/
static Class getIBOBeanClassFor(Class entityInterfaceClass)
{
return getInstance().getBeanClassForNonStatic(entityInterfaceClass);
}
/**
* Gets the Class object for the (BMP) bean class of a data bean.
* @param entityInterfaceClass i the (Remote) interface of the data bean.
*/
protected Class getBeanClassForNonStatic(Class entityInterfaceClass)
{
try
{
Class beanClass = (Class) getBeanClassesMap().get(entityInterfaceClass);
if (beanClass == null)
{
if (entityInterfaceClass.isInterface())
{
String className = entityInterfaceClass.getName();
String beanClassName = className + getBeanSuffix();
beanClass = RefactorClassRegistry.forName(beanClassName);
getBeanClassesMap().put(entityInterfaceClass, beanClass);
getInterfaceClassesMap().put(beanClass, entityInterfaceClass);
}
else
{
beanClass = entityInterfaceClass;
}
}
return beanClass;
}
catch (Exception e)
{
//e.printStackTrace();
throw new RuntimeException(e.getClass().getName() + ": " + e.getMessage());
}
//return null;
}
/**
* Gets the Class object for the (Remote) interface of a data bean.
* @param entityBeanOrInterfaceClass can be either the BMP bean class or the interface class itself.
*/
protected Class getInterfaceClassForNonStatic(Class entityBeanOrInterfaceClass)
{
if (entityBeanOrInterfaceClass.isInterface())
{
return entityBeanOrInterfaceClass;
}
else
{
Class interfaceClass = (Class) getInterfaceClassesMap().get(entityBeanOrInterfaceClass);
try
{
if (interfaceClass == null)
{
String className = entityBeanOrInterfaceClass.getName();
int endIndex = className.indexOf(getBeanSuffix());
if (endIndex != -1)
{
String interfaceClassName = className.substring(0, endIndex);
interfaceClass = RefactorClassRegistry.forName(interfaceClassName);
getBeanClassesMap().put(interfaceClass, entityBeanOrInterfaceClass);
getInterfaceClassesMap().put(entityBeanOrInterfaceClass, interfaceClass);
}
else
{
//For legacy beans
interfaceClass = entityBeanOrInterfaceClass;
}
}
return interfaceClass;
}
catch (ClassNotFoundException e)
{
throw new RuntimeException(e.getClass() + ": " + e.getMessage());
}
}
}
private Map getServicesMap(IWApplicationContext iwac)
{
/**
* @todo: implement
*/
return getServicesMap();
}
private Map getServicesMap()
{
if (this.services == null)
{
this.services = new HashMap();
}
return this.services;
}
/**
* Clears all cached object instaces of looked up objects (Home instances etc.)
**/
public static synchronized void clearAllCache()
{
getInstance().getHomesMap().clear();
getInstance().getBeanClassesMap().clear();
getInstance().getInterfaceClassesMap().clear();
}
protected Object getHomeThroughJNDI(Class beanInterfaceClass)throws RemoteException{
Object home = null;
try{
InitialContext jndiContext = getInitialContext();
Object homeObj = jndiContext.lookup(getBeanClassForNonStatic(beanInterfaceClass).getName());
//home = (ResponseHome) jndiContext.lookup("java:comp/env/"+ResponseBMPBean.class.getName());
home = PortableRemoteObject.narrow(homeObj, getHomeInterfaceClassFor(beanInterfaceClass));
return home;
}
catch(Exception e){
throw new RemoteException("Error looking up home for "+beanInterfaceClass.getName()+". Errormessage was: "+e.getMessage());
}
}
protected boolean doLookupOverJNDI(Class beanInterfaceClass){
/**
*@todo: implement
**/
return false;
}
private InitialContext getInitialContext() throws NamingException{
if(this.jndiProperties==null){
this.jndiProperties=new Properties();
try {
this.jndiProperties.load(new FileInputStream("/idega/jndi.properties"));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return new InitialContext(this.jndiProperties);
}
public Map getBeanClassesMap(){
if(this.beanClasses==null){
this.beanClasses = new HashMap();
}
return this.beanClasses;
}
public Map getInterfaceClassesMap(){
if(this.interfaceClasses==null){
this.interfaceClasses= new HashMap();
}
return this.interfaceClasses;
}
public Map getHomesMap(){
if(this.homes==null){
this.homes= new HashMap();
}
return this.homes;
}
public static void registerImplementationForBean(Class interfaceClass, Class beanClass) {
getInstance().getBeanClassesMap().put(interfaceClass,beanClass);
getInstance().getInterfaceClassesMap().put(beanClass,interfaceClass);
}
}