Java tutorial
/** * Copyright (C) 2012 52North Initiative for Geospatial Open Source Software GmbH * * 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.n52.movingcode.runtime.processors; import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; import org.apache.commons.io.FileUtils; import org.n52.movingcode.runtime.codepackage.MovingCodePackage; import org.n52.movingcode.runtime.processors.config.ProcessorConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import de.tudresden.gis.geoprocessing.movingcode.schema.PackageDescriptionDocument.PackageDescription; import de.tudresden.gis.geoprocessing.movingcode.schema.PlatformType; /** * This singleton class is responsible for managing and delivering processors that can digest the code * contained in the moving code packages. * * @author Matthias Mueller, TU Dresden * */ public class ProcessorFactory { private static ProcessorFactory instance; private Map<String, String[]> supportedContainers; private String[] availablePlatforms = ProcessorConfig.getDefaultPlatforms(); private Map<String, File> scratchworkspaceMap; private Map<String, PropertyMap> processorProperties; private static final Logger LOGGER = LoggerFactory.getLogger(ProcessorFactory.class); private ProcessorFactory() { super(); initConfig(); } /** * Delivers a new {@link AbstractProcessor} that is able to handle the mcPackage passed in the method * call. * * @param mcPackage * @return {@link AbstractProcessor} * */ public AbstractProcessor newProcessor(final MovingCodePackage mcPackage) { String processorID = findCompatibleProcessor(mcPackage.getDescriptionAsDocument().getPackageDescription()); if (processorID != null) { LOGGER.debug("Creating new processor for package: " + mcPackage.getPackageId().toString()); return loadProcessor(processorID, getScratchworkspace(processorID), mcPackage, getProcessorProperties(processorID)); } else { LOGGER.debug("Could not find a suitable processor for package: " + mcPackage.getPackageId().toString()); return null; // if no suitable processor was found } } public boolean supportsPackage(final MovingCodePackage mcPackage) { String processorID = findCompatibleProcessor(mcPackage.getDescriptionAsDocument().getPackageDescription()); // return true if processorID is not null return processorID != null ? true : false; } public static synchronized ProcessorFactory getInstance() { if (instance == null) { instance = new ProcessorFactory(); } return instance; } /** * Load configuration from the config file. */ private void initConfig() { this.supportedContainers = new HashMap<String, String[]>(); this.scratchworkspaceMap = new HashMap<String, File>(); this.processorProperties = new HashMap<String, PropertyMap>(); try { // deal with individual processors for (String processorId : ProcessorConfig.getRegisteredProcessorIDs()) { this.supportedContainers.put(processorId, ProcessorConfig.getSupportedContainers(processorId)); String workspace = ProcessorConfig.getWorkspace(processorId); // create and check temp workspace // register this temp WS in the private Map File scratchWS; // check for $TEMP$ token if (workspace.equals(ProcessorConfig.randomTempDirToken)) { scratchWS = newTempDir(); } else { scratchWS = new File(workspace); // attempt to create directories if they don't exist scratchWS.mkdirs(); } // TODO: check if temp dir really exists; if not: throw an error this.scratchworkspaceMap.put(processorId, scratchWS); PropertyMap pMap = new PropertyMap(); pMap.putAll(ProcessorConfig.getProperties(processorId)); this.processorProperties.put(processorId, pMap); } } catch (Exception e) { LOGGER.error(e.getMessage()); } } /** * Loader for processor classes. Uses dynamic class loading and returns {@link AbstractProcessor}. If the * class loading and instantiation should fail for some reason NULL is returned. * * @param processorClassName * @param scratchworkspace * @param mcp * @param properties * @return {@link AbstractProcessor} */ private AbstractProcessor loadProcessor(String processorClassName, final File scratchworkspace, final MovingCodePackage mcp, final PropertyMap properties) { try { // load class Class<?> processorClass = ProcessorFactory.class.getClassLoader().loadClass(processorClassName); // get a suitable constructor Constructor<?> processorConstructor = processorClass.getDeclaredConstructor(File.class, MovingCodePackage.class, PropertyMap.class); // return new Object return (AbstractProcessor) processorConstructor.newInstance(scratchworkspace, mcp, properties); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception e) { // catch everything else e.printStackTrace(); } return null; } /** * Getter for registered processors. * * @return Array of {@link String} containing the IDs of the registered processors. */ public String[] registeredProcessors() { return this.supportedContainers.keySet().toArray(new String[this.supportedContainers.keySet().size()]); } /** * Getter for registered platforms. * * @return Array of {@link String} containing the IDs of the registered platforms. */ public String[] getAvailablePlatforms() { return this.availablePlatforms; } /** * @param {@link String} processorID * @return {@link File} scatchworkspace assigned to a processor class */ public File getScratchworkspace(String processorID) { return this.scratchworkspaceMap.get(processorID); } /** * Getter for properties arrays. Currently for informative use only. * * @param {@link String} processorID * @return {@link PropertyMap} */ public PropertyMap getProcessorProperties(String processorID) { return this.processorProperties.get(processorID); } /** * Helper method: Does an array of Strings contain a particular String? Comparison is case-insensitive. * * @param haystack * - Array of Strings * @param needle * - String to be searched * @return boolean - true if haystack contains the needle, false if not. */ private static final boolean needleInHaystack(final String[] haystack, final String needle) { for (String currentItem : haystack) { if (currentItem.equalsIgnoreCase(needle)) { return true; } } return false; } /** * Helper method: Does an array of Strings contain a particular set of Strings? Comparison is * case-insensitive. * * @param haystack * - Array of Strings * @param needles * - Strings to be searched * @return boolean - true if haystack contains all the needles, false if not. */ private static final boolean allNeedlesInHaystack(final String[] haystack, final String[] needles) { for (String currentNeedle : needles) { // if one of the needles is missing return false if (!needleInHaystack(haystack, currentNeedle)) { return false; } } return true; } /** * Lookup method that returns the first processor's ID that is compatible with the description. If no * appropriate processor is found NULL is returned. * * @param {@link PackageDescription} description * @return {@link String} processorID */ private String findCompatibleProcessor(final PackageDescription description) { PlatformType[] validPlatforms = description.getPlatformArray(); // 1. Do we have some required platforms in place? boolean inPlace = false; for (PlatformType currentPlatform : validPlatforms) { // platforms defined using attribute syntax if (currentPlatform.isSetPlatformId()) { if (needleInHaystack(this.availablePlatforms, currentPlatform.getPlatformId())) { inPlace = true; break; } } // platforms defined by the array if (allNeedlesInHaystack(this.availablePlatforms, currentPlatform.getRequiredRuntimeComponentArray())) { inPlace = true; break; } } if (!inPlace) { return null; } String requiredContainer = description.getWorkspace().getContainerType(); // 2. return a processor that supports the particular container // if no processor supports this container return null for (String currentID : this.supportedContainers.keySet()) { if (needleInHaystack(this.supportedContainers.get(currentID), requiredContainer)) { // return first applicable processor return currentID; } } return null; } private static final File newTempDir() { File tmpDir = FileUtils.getTempDirectory(); File newTmpFolder = new File(tmpDir, AUID.randomAUID()); newTmpFolder.mkdir(); newTmpFolder.deleteOnExit(); return newTmpFolder; } }