All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.marvelution.hudson.plugins.apiv2.wink.HudsonWinkApplication Maven / Gradle / Ivy

There is a newer version: 5.0.4
Show newest version
/*
 * Licensed to Marvelution under one or more contributor license 
 * agreements.  See the NOTICE file distributed with this work 
 * for additional information regarding copyright ownership.
 * Marvelution licenses this file to you 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 com.marvelution.hudson.plugins.apiv2.wink;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.wink.common.WinkApplication;
import org.apache.wink.common.annotations.Parent;
import org.apache.wink.common.internal.registry.metadata.ProviderMetadataCollector;
import org.apache.wink.common.internal.registry.metadata.ResourceMetadataCollector;

import com.marvelution.hudson.plugins.apiv2.resources.impl.BaseRestResource;
import com.marvelution.hudson.plugins.apiv2.utils.HudsonPluginUtils;

/**
 * {@link WinkApplication} implementation specific for Hudson
 * 
 * @author Mark rekveld
 */
public class HudsonWinkApplication extends WinkApplication {

	public static final String[] DEFAULT_APPLICATION_RESOURCE_PACKAGES = {
		"com.marvelution.hudson.plugins.apiv2.resources",
	};

	private static final Logger LOGGER = Logger.getLogger(HudsonWinkApplication.class.getName());

	private Set> jaxRSClasses = null;

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Set> getClasses() {
		if (jaxRSClasses == null) {
			jaxRSClasses = new HashSet>();
			final Set> classes = new HashSet>();
			for (String resourcePackageName : DEFAULT_APPLICATION_RESOURCE_PACKAGES) {
				try {
					Enumeration resources = HudsonPluginUtils.getPluginClassloader().getResources(resourcePackageName.replace(".", "/"));
					while (resources.hasMoreElements()) {
						URL resource = resources.nextElement();
						if (resource.getProtocol().equalsIgnoreCase("jar")) {
							// Load resources from the JAR file
							JarURLConnection connection = (JarURLConnection) resource.openConnection();
							classes.addAll(getClassesFromJarFile(connection.getJarFile(), resourcePackageName));
						} else if (resource.getProtocol().equalsIgnoreCase("file")) {
							// Load resources form File system
							classes.addAll(getClassesFromPackage(new File(resource.getFile()), resourcePackageName));
						} else {
							LOGGER.info("Skipping resource [" + resource.toString() + "]; Unsupport resource protocol");
						}
					}
				} catch (IOException e) {
				}
			}
			processClasses(classes);
			LOGGER.info("Loaded all REST Resource/Provider classes");
		}
		return jaxRSClasses;
	}

	/**
	 * Get all the classes that are located in a source package.
	 * All sub packages are also processed.
	 * 
	 * @param baseResource the {@link File} base resource to load from
	 * @param resourcePackageName the source package to get all the classes for
	 * @return {@link Set} of {@link Class} objects that are located in the source package or one of its sub packages
	 */
	private Set> getClassesFromPackage(File baseResource, String resourcePackageName) {
		Set> classes = new HashSet>();
		for (File file : baseResource.listFiles()) {
			if (file.isFile() && file.getName().endsWith(".class")) {
				final String className = file.getName().substring(0, file.getName().lastIndexOf('.'));
				try {
					classes.add(Class.forName(resourcePackageName + "." + className));
					LOGGER.log(Level.FINE, "Loaded Resource: " + resourcePackageName + "." + className);
				} catch (ClassNotFoundException e) {
					LOGGER.log(Level.SEVERE, "Failed to load REST Resources: " + resourcePackageName
						+ "." + className, e);
				}
			} else {
				classes.addAll(getClassesFromPackage(file, resourcePackageName + "." + file.getName()));
			}
		}
		return classes;
	}

	/**
	 * Get all the classes that are in a {@link JarFile} and that are in the given package
	 * 
	 * @param jarFile the {@link JarFile} to filter
	 * @param resourcePackageName the package to filter with
	 * @return {@link Set} of {@link Class} objects
	 * 
	 * @since 4.1.0
	 */
	private Set> getClassesFromJarFile(JarFile jarFile, String resourcePackageName) {
		Set> classes = new HashSet>();
		Enumeration entries = jarFile.entries();
		while (entries.hasMoreElements()) {
			JarEntry jarEntry = entries.nextElement();
			if (!jarEntry.isDirectory() && jarEntry.getName().endsWith(".class")) {
				String className = jarEntry.getName().substring(0, jarEntry.getName().lastIndexOf('.'));
				className = className.replaceAll("/", ".");
				if (className.startsWith(resourcePackageName)) {
					try {
						classes.add(Class.forName(className));
						LOGGER.log(Level.FINE, "Loaded Resource: " + className);
					} catch (ClassNotFoundException e) {
						LOGGER.log(Level.SEVERE, "Failed to load REST Resources: " + className, e);
					}
				}
			}
		}
		return classes;
	}

	/**
	 * Process the given {@link Set} of {@link Class} objects and add them to the JAX-RS Class List if they are valid
	 * JAX-RS Classes
	 * 
	 * @param classes {@link Set} of {@link Class} objects to process
	 */
	private void processClasses(Set> classes) {
		for (Class cls : classes) {
			if (ProviderMetadataCollector.isProvider(cls)) {
				LOGGER.log(Level.FINE, "Loaded REST Provider class: " + cls.getName());
				jaxRSClasses.add(cls);
			} else if (ResourceMetadataCollector.isResource(cls)) {
				final Parent parent = (Parent) cls.getAnnotation(Parent.class);
				if ((parent != null && BaseRestResource.class.equals(parent.value()))) {
					LOGGER.log(Level.FINE, "Loaded REST Resource class: " + cls.getName());
					jaxRSClasses.add(cls);
				} else if (BaseRestResource.class.equals(cls)) {
					LOGGER.log(Level.FINE, "Loaded Base REST Resource class: " + cls.getName());
					jaxRSClasses.add(cls);
				} else {
					LOGGER.log(Level.FINE, "Class [" + cls.getName() + "] is not a valid REST Resource, "
						+ "the @Parent(RestBaseResource.class) annotation is missing");
				}
			} else {
				LOGGER.log(Level.FINE, "Skipping class [" + cls.getName() + "]; Its not a REST Resource or Provider");
			}
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy