/*
* Copyright 2013 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.rest.core.registry;
import java.util.Iterator;
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;
/**
* Scanner for rest services
*
* @author Thiago da Rosa de Bustamante
*
*/
public class RestServiceFactoryImpl implements RestServiceFactory
{
private static boolean initialized = false;
private static final Log logger = LogFactory.getLog(RestServiceFactoryImpl.class);
private ScanningStrategy strategy;
/**
* This Constructor select the best strategy to use.
*/
public RestServiceFactoryImpl()
{
if (Environment.isProduction() || Boolean.parseBoolean(ConfigurationFactory.getConfigurations().useCompileTimeClassScanningForDevelopment()))
{
strategy = new CompileTimeStrategy();
}
else
{
strategy = new RuntimeStrategy();
}
}
@Override
public Object getService(Class<?> serviceClass)
{
try
{
return serviceClass.newInstance();
}
catch (Exception e)
{
String msg = "Error creating REST service for class [" + serviceClass.getCanonicalName() + "].";
logger.error(msg, e);
throw new RuntimeException(msg, e);
}
}
/**
*
* @param serviceName
* @return
*/
public Class<?> getServiceClass(String serviceName)
{
initialize(null);
try
{
return Class.forName(strategy.getServiceClassName(serviceName));
}
catch (ClassNotFoundException e)
{
String msg = "Can not found class associated with service ["+serviceName+"]";
logger.error(msg, e);
throw new RuntimeException(msg, e);
}
}
@Override
public void initialize(ServletContext context)
{
if (initialized)
{
return;
}
if (!strategy.initialize(context))
{
if (strategy instanceof CompileTimeStrategy)
{
logger.info("REST services map not found. Using runtime strategy for services...");
strategy = new RuntimeStrategy();
strategy.initialize(context);
}
else
{
logger.error("Error initializing REST services.");
}
}
initialized = true;
}
public Iterator<String> iterateRestServices()
{
initialize(null);
return strategy.iterateRestServices();
}
/**
* This class uses a file generated during application compilation to find out rest service classes.
*
* @author Thiago da Rosa de Bustamante
*
*/
private static class CompileTimeStrategy implements ScanningStrategy
{
public String getServiceClassName(String serviceName)
{
return RestServicesCompileMap.getService(serviceName);
}
public boolean initialize(ServletContext context)
{
return RestServicesCompileMap.initialize();
}
@Override
public Iterator<String> iterateRestServices()
{
return RestServicesCompileMap.iterateServices();
}
}
/**
* This class scan the application classpath to build a map of
* rest service implementations and uses it to find out which
* class it must use to each service path. 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 ScanningStrategy
{
public String getServiceClassName(String serviceName)
{
return RestServices.getService(serviceName);
}
public boolean initialize(ServletContext context)
{
return true;
}
@Override
public Iterator<String> iterateRestServices()
{
return RestServices.iterateServices();
}
}
/**
* Describes a strategy for service scanning.
* @author Thiago da Rosa de Bustamante
*/
private static interface ScanningStrategy
{
String getServiceClassName(String serviceName);
boolean initialize(ServletContext context);
Iterator<String> iterateRestServices();
}
}