/*
* Copyright 2011 cruxframework.org.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.cruxframework.crux.core.server.dispatch;
import javax.servlet.ServletContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cruxframework.crux.core.config.ConfigurationFactory;
import org.cruxframework.crux.core.server.Environment;
/**
* Default ServiceFactory implementation. It will use the first implementation found
* to the given interface passed.
*
* @author Thiago da Rosa de Bustamante
*
*/
public class ServiceFactoryImpl implements ServiceFactory
{
private static boolean initialized = false;
private static final Log logger = LogFactory.getLog(ServiceFactoryImpl.class);
private FactoryStrategy strategy;
/**
* This Constructor select the best strategy to use.
*/
public ServiceFactoryImpl()
{
if (Environment.isProduction() || Boolean.parseBoolean(ConfigurationFactory.getConfigurations().useCompileTimeClassScanningForDevelopment()))
{
strategy = new CompileTimeStrategy();
}
else
{
strategy = new RuntimeStrategy();
}
}
/**
* @see org.cruxframework.crux.core.server.dispatch.ServiceFactory#getService(java.lang.String)
*/
public Object getService(String serviceName)
{
initialize(null);
return strategy.getService(serviceName);
}
/**
* @see org.cruxframework.crux.core.server.dispatch.ServiceFactory#initialize(javax.servlet.ServletContext)
*/
public void initialize(ServletContext context)
{
if (initialized)
{
return;
}
if (!strategy.initialize(context))
{
if (strategy instanceof CompileTimeStrategy)
{
logger.info("RPC services map not found. Using runtime strategy for services...");
strategy = new RuntimeStrategy();
strategy.initialize(context);
}
else
{
logger.error("Error initializing RPC services.");
}
}
initialized = true;
}
/**
* This class uses a file generated during application compilation to find out which
* class it must instantiate to each interface service.
*
* @author Thiago da Rosa de Bustamante
*
*/
private static class CompileTimeStrategy implements FactoryStrategy
{
public Object getService(String serviceName)
{
try
{
return ServicesCompileMap.getService(serviceName).newInstance();
}
catch (Exception e)
{
throw new RuntimeException("Error creating service ["+serviceName+"].", e);
}
}
public boolean initialize(ServletContext context)
{
return ServicesCompileMap.initialize(context);
}
}
/**
* Describes a strategy for service instantiation.
* @author Thiago da Rosa de Bustamante
*/
private static interface FactoryStrategy
{
/**
* @see org.cruxframework.crux.core.server.dispatch.ServiceFactory#getService(java.lang.String)
*/
Object getService(String serviceName);
/**
* @see org.cruxframework.crux.core.server.dispatch.ServiceFactory#initialize(javax.servlet.ServletContext)
*/
boolean initialize(ServletContext context);
}
/**
* This class scan the application classpath to the first class to build a map of
* interfaces implementations and uses it to find out which
* class it must instantiate to each interface service. For debug purposes, it is
* better, once it supports hot deployment of resources, but it waste memory in
* production.
*
* @author Thiago da Rosa de Bustamante
*/
private static class RuntimeStrategy implements FactoryStrategy
{
public Object getService(String serviceName)
{
try
{
return Services.getService(serviceName).newInstance();
}
catch (Exception e)
{
throw new RuntimeException("Error creating service ["+serviceName+"].", e);
}
}
public boolean initialize(ServletContext context)
{
return true;
}
}
}