/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.everrest.groovy.servlet;
import org.codehaus.groovy.control.CompilationFailedException;
import org.everrest.core.Filter;
import org.everrest.core.servlet.EverrestServletContextInitializer;
import org.everrest.groovy.DefaultGroovyResourceLoader;
import org.everrest.groovy.GroovyClassLoaderProvider;
import org.everrest.groovy.ScriptFinder;
import org.everrest.groovy.ScriptFinderFactory;
import org.everrest.groovy.SourceFile;
import org.everrest.groovy.URLFilter;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletContext;
import javax.ws.rs.Path;
import javax.ws.rs.core.Application;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
/**
* @author andrew00x
*/
public class GroovyEverrestServletContextInitializer extends EverrestServletContextInitializer {
private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(GroovyEverrestServletContextInitializer.class);
public static final String EVERREST_GROOVY_ROOT_RESOURCES = "org.everrest.groovy.root.resources";
public static final String EVERREST_GROOVY_APPLICATION = "org.everrest.groovy.Application";
public static final String EVERREST_GROOVY_SCAN_COMPONENTS = "org.everrest.groovy.scan.components";
protected final GroovyClassLoaderProvider classLoaderProvider;
protected final URL[] groovyClassPath;
public GroovyEverrestServletContextInitializer(ServletContext sctx) {
super(sctx);
classLoaderProvider = new GroovyClassLoaderProvider();
try {
String rootResourcesParameter = getParameter(EVERREST_GROOVY_ROOT_RESOURCES);
if (rootResourcesParameter != null) {
String[] tokens = rootResourcesParameter.split(",");
groovyClassPath = new URL[tokens.length];
for (int i = 0; i < tokens.length; i++) {
groovyClassPath[i] = URI.create(tokens[i]).toURL();
}
} else {
groovyClassPath = new URL[0];
}
classLoaderProvider.getGroovyClassLoader().setResourceLoader(new DefaultGroovyResourceLoader(groovyClassPath));
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
@SuppressWarnings({"unchecked"})
@Override
public Application getApplication() {
final String groovyApplicationFQN = getParameter(EVERREST_GROOVY_APPLICATION);
final boolean scan = getBoolean(EVERREST_GROOVY_SCAN_COMPONENTS, false);
Application groovyApplication = null;
if (groovyApplicationFQN != null) {
if (scan) {
LOG.warn("Scan of Groovy JAX-RS components is disabled cause to specified 'org.everrest.groovy.Application'.");
}
Class<?> applicationClass;
try {
applicationClass = classLoaderProvider.getGroovyClassLoader().loadClass(groovyApplicationFQN, true, false);
groovyApplication = (Application)applicationClass.newInstance();
} catch (CompilationFailedException | IllegalAccessException | InstantiationException | ClassNotFoundException e) {
throw new RuntimeException(e);
}
} else if (scan) {
try {
final Set<Class<?>> scanned = new HashSet<>();
final Class[] jaxrsAnnotations = new Class[]{Path.class, Provider.class, Filter.class};
final URLFilter filter = new URLFilter() {
@Override
public boolean accept(URL url) {
return url.getPath().endsWith(".groovy");
}
};
for (int i = 0; i < groovyClassPath.length; i++) {
final URL path = groovyClassPath[i];
final String protocol = path.getProtocol();
ScriptFinder finder = ScriptFinderFactory.getScriptFinder(protocol);
if (finder != null) {
URL[] scripts = finder.find(filter, path);
if (scripts != null && scripts.length > 0) {
SourceFile[] files = new SourceFile[scripts.length];
for (int k = 0; k < scripts.length; k++) {
files[k] = new SourceFile(scripts[k]);
}
Class[] classes = classLoaderProvider.getGroovyClassLoader().parseClasses(files);
for (int k = 0; k < classes.length; k++) {
Class clazz = classes[k];
if (findAnnotation(clazz, jaxrsAnnotations)) {
boolean added = scanned.add(clazz);
if (added) {
if (LOG.isDebugEnabled()) {
LOG.debug("Add class : {}", clazz);
}
} else {
LOG.warn("Skip duplicated class: {}", clazz);
}
}
}
}
} else {
LOG.warn("Skip URL : {}. Protocol '{}' is not supported for scan JAX-RS components", path, protocol);
}
}
groovyApplication = new Application() {
@Override
public Set<Class<?>> getClasses() {
return scanned;
}
};
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return groovyApplication;
}
private boolean findAnnotation(Class<?> clazz, Class<? extends Annotation>... annClasses) {
for (Class<? extends Annotation> ac : annClasses) {
if (clazz.getAnnotation(ac) != null) {
return true;
}
}
return false;
}
}