/*******************************************************************************
* Signavio Core Components
* Copyright (C) 2012 Signavio GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package com.signavio.platform.core;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import javax.servlet.ServletContext;
import com.signavio.platform.handler.AbstractHandler;
import com.signavio.platform.handler.BasisHandler;
/**
* HandlerManager implements the manager to hold all HandlerEntries.
* @author Willi
*
*/
public class HandlerDirectory extends HashMap<String, HandlerEntry> implements Directory {
/**
* Define private variables
*/
private static final long serialVersionUID = 1L;
private ServletContext servletContext;
/**
* To create get a new instance of the HandlerManager
* @deprecated Use System.getInstance().getHandlerManger() instead
* @return
*/
@Deprecated
public static HandlerDirectory getInstance(){
return Platform.getInstance().getHandlerDirectory();
}
public HandlerDirectory(ServletContext sc) {
super();
this.servletContext = sc;
}
/**
* Get all Handlers from a particular context
* @param context
* @return
*/
public Collection<HandlerEntry> getAllHandlerByContext(Class<? extends BasisHandler> context){
Collection<HandlerEntry> res = new ArrayList<HandlerEntry>();
// For every Handler
for( HandlerEntry he : this.values() )
{
// try to find a Handler where the name is equal than the name of the class
if( he.getContextClass() != null && context.equals(he.getContextClass()) )
{
res.add(he);
}
}
return res;
}
/**
* Get all BasisHandler for a particular URI
* @param uri
* @return
*/
public HandlerEntry getBasisHandler(String uri){
// Add leading /
if( uri.charAt(0) != '/' )
uri = '/' + uri;
// For every Handler
for( HandlerEntry he : this.values() )
{
// try to find one, where the context is empty, the class is inherit from the BasisHandler and the uri is equals to the given uri
if( he.getContextClass() == null && BasisHandler.class.isAssignableFrom(he.handlerClass) && he.getUri().equals(uri) )
{
return he;
}
}
return null;
}
/**
* Get a Handler by their URI of the context and the URI of the Handler
* @param contexturi Defines the URI of the context
* @param uri Defines the URI for the Handler
* @return
*/
public HandlerEntry getHandlerByContextAndUri(String contexturi, String uri){
// Add leading /
if( uri.charAt(0) != '/' )
uri = '/' + uri;
// Get the context class from the given context URI
HandlerEntry contextClass = this.getBasisHandler( contexturi );
// For every Handler
for( HandlerEntry he : this.values() )
{
// try to find one, without a context class equals the given context, and equal the given URI
if( he.getContextClass() != null && he.getContextClass() == contextClass.getHandlerClass() && he.getUri().equals(uri) )
{
return he;
}
}
return null;
}
/**
* Get all list of all classes within a package,
* including all child packages
* @param pckgname
* @return
* @throws ClassNotFoundException
*/
@SuppressWarnings("unchecked")
private static List<Class<? extends AbstractHandler>> getClassesByPackageName(String pckgname) throws ClassNotFoundException {
// This will hold a list of directories matching the packagename. There may be more than one if a package is split over multiple jars/paths
ArrayList<File> directories = new ArrayList<File>();
try {
ClassLoader cld = Thread.currentThread().getContextClassLoader();
if (cld == null) {
throw new ClassNotFoundException("Can't get class loader.");
}
String path = pckgname.replace('.', '/');
// Ask for all resources for the path
Enumeration<URL> resources = cld.getResources(path);
while (resources.hasMoreElements()) {
directories.add(new File(URLDecoder.decode(resources.nextElement().getPath(), "UTF-8")));
}
} catch (NullPointerException x) {
throw new ClassNotFoundException(pckgname + " does not appear to be a valid package (Null pointer exception)");
} catch (UnsupportedEncodingException encex) {
throw new ClassNotFoundException(pckgname + " does not appear to be a valid package (Unsupported encoding)");
} catch (IOException ioex) {
throw new ClassNotFoundException("IOException was thrown when trying to get all resources for " + pckgname);
}
ArrayList<Class<? extends AbstractHandler>> classes = new ArrayList<Class<? extends AbstractHandler>>();
// For every directory identified capture all the .class files
for (File directory : directories) {
if (directory.exists()) {
// Get the list of the files contained in the package
File[] files = directory.listFiles();
for (File file : files) {
// we are only interested in .class files
if (file.getName().endsWith(".class")) {
// removes the .class extension
// Get the class object
Class<? extends Object> cls = Class.forName(pckgname + '.' + file.getName().substring(0, file.getName().length() - 6));
// Checks if its an AbstractHandler
if( AbstractHandler.class.isAssignableFrom(cls) ){
classes.add( (Class<? extends AbstractHandler>) cls );
}
} else if( file.isDirectory() ) {
// Add recursive all child packages
List<Class<? extends AbstractHandler>> childPackages = HandlerDirectory.getClassesByPackageName( pckgname + '.' + file.getName() );
classes.addAll( childPackages );
}
}
} else {
throw new ClassNotFoundException(pckgname + " (" + directory.getPath() + ") does not appear to be a valid package");
}
}
return classes;
}
public void registerHandlersOfPackage(String packageName) {
// Try to get all Handler Classes and instantiate the HandlerEntries with it
try {
for( Class<? extends AbstractHandler> cls : HandlerDirectory.getClassesByPackageName(packageName) )
{
// If the class is an abstract class --> continue
if( Modifier.isAbstract( cls.getModifiers() ) )
{
continue;
}
// Create a new HandlerEntry with the given classifier
HandlerEntry he = new HandlerEntry(cls);
// If there is no handler class, something
// might be wrong, --> continue.
if( he.getHandlerClass() == null )
{
continue;
}
// Try to instantiate the Handler
Constructor co = cls.getConstructor(ServletContext.class);
he.setHandlerInstance( (AbstractHandler)(co.newInstance( this.servletContext )) );
// Add the classifier to the map
this.put(cls.getName(), he);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* TODO: This method is for debugging purpose only. It is called at system initialization
*/
private void registerHandlers() {
this.registerHandlersOfPackage("com.signavio.editor.handler");
this.registerHandlersOfPackage("com.signavio.editor.stencilset.handler");
this.registerHandlersOfPackage("com.signavio.explorer.handler");
this.registerHandlersOfPackage("com.signavio.platform.config.handler");
this.registerHandlersOfPackage("com.signavio.usermanagement.user.handler");
this.registerHandlersOfPackage("com.signavio.warehouse.directory.handler");
this.registerHandlersOfPackage("com.signavio.warehouse.model.handler");
this.registerHandlersOfPackage("com.signavio.warehouse.revision.handler");
this.registerHandlersOfPackage("com.signavio.warehouse.search.handler");
}
public void start() {
registerHandlers();
}
public void stop() {
// TODO Auto-generated method stub
}
}