Java tutorial
package de.zib.gndms.infra.system; /* * Copyright 2008-2011 Zuse Institute Berlin (ZIB) * * 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. */ import com.google.common.collect.Maps; import com.google.inject.*; import de.zib.gndms.infra.access.ServiceHomeProvider; import de.zib.gndms.infra.service.GNDMPersistentServiceHome; import de.zib.gndms.infra.service.GNDMServiceHome; import de.zib.gndms.infra.service.GNDMSingletonServiceHome; import de.zib.gndms.kit.access.GNDMSBinding; import de.zib.gndms.kit.configlet.DefaultConfiglet; import de.zib.gndms.kit.monitor.GroovyBindingFactory; import de.zib.gndms.kit.monitor.GroovyMoniServer; import de.zib.gndms.logic.model.TaskAction; import de.zib.gndms.logic.access.TaskActionProvider; import de.zib.gndms.logic.model.gorfx.*; import de.zib.gndms.kit.access.InstanceProvider; import de.zib.gndms.model.common.ConfigletState; import de.zib.gndms.model.common.GridResource; import de.zib.gndms.model.common.ModelUUIDGen; import de.zib.gndms.model.common.types.factory.IndustrialPark; import de.zib.gndms.model.common.types.factory.KeyFactory; import de.zib.gndms.model.common.types.factory.KeyFactoryInstance; import de.zib.gndms.model.common.types.factory.RecursiveKeyFactory; import de.zib.gndms.model.gorfx.OfferType; import de.zib.gndms.stuff.BoundInjector; import de.zib.gndms.kit.configlet.ConfigletProvider; import de.zib.gndms.kit.configlet.Configlet; import de.zib.gndms.kit.system.SystemInfo; import groovy.lang.Binding; import groovy.lang.GroovyShell; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.globus.wsrf.ResourceException; import org.jetbrains.annotations.NotNull; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Query; import java.lang.reflect.InvocationTargetException; import java.security.Principal; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; /** * ThingAMagic. * * @see GNDMSystem * @author try ste fan pla nti kow zib * @version $Id$ * * User: stepn Date: 03.09.2008 Time: 16:50:06 */ public class GNDMSystemDirectory implements SystemDirectory, Module { private @NotNull final Log logger = LogFactory.getLog(GNDMSystemDirectory.class); private static final int INITIAL_CAPACITY = 32; private static final long INSTANCE_RETRIEVAL_INTERVAL = 250L; private final @NotNull String systemName; /** * stores several instances needed for the <tt>GNDMSystem</tt> */ private final @NotNull Map<String, Object> instances; private final @NotNull Map<Class<? extends GridResource>, GNDMPersistentServiceHome<?>> homes; private final Map<String, Configlet> configlets = Maps.newConcurrentHashMap(); @SuppressWarnings({ "RawUseOfParameterizedType" }) private final @NotNull IndustrialPark<OfferType, String, AbstractORQCalculator<?, ?>> orqPark; @SuppressWarnings({ "RawUseOfParameterizedType" }) private final @NotNull IndustrialPark<OfferType, String, ORQTaskAction<?>> taskActionPark; @SuppressWarnings({ "FieldCanBeLocal" }) private final Wrapper<Object> sysHolderWrapper; private final @NotNull ModelUUIDGen uuidGen; private final @NotNull BoundInjector boundInjector = new BoundInjector(); @SuppressWarnings({ "ThisEscapedInObjectConstruction" }) GNDMSystemDirectory(final @NotNull String sysNameParam, final @NotNull ModelUUIDGen uuidGenParam, final Wrapper<Object> systemHolderWrapParam, final @NotNull Module sysModule) { instances = new HashMap<String, Object>(INITIAL_CAPACITY); homes = new HashMap<Class<? extends GridResource>, GNDMPersistentServiceHome<?>>(INITIAL_CAPACITY); systemName = sysNameParam; uuidGen = uuidGenParam; sysHolderWrapper = systemHolderWrapParam; final Injector injector = Guice.createInjector(sysModule, this); boundInjector.setInjector(injector); GNDMSBinding.setDefaultInjector(injector); final ORQCalculatorMetaFactory calcMF = new ORQCalculatorMetaFactory(); calcMF.setInjector(injector); calcMF.setWrap(sysHolderWrapper); orqPark = new OfferTypeIndustrialPark<AbstractORQCalculator<?, ?>>(calcMF); final ORQTaskActionMetaFactory taskMF = new ORQTaskActionMetaFactory(); taskMF.setWrap(sysHolderWrapper); taskMF.setInjector(injector); taskActionPark = new OfferTypeIndustrialPark<ORQTaskAction<?>>(taskMF); } /** * Adds the <tt>GNDMServiceHome</tt> and the corresponding <tt>org.globus.wsrf.Resource</tt> to the {@link #instances} map * * @param home a GNDMS Service resource home instance * @throws ResourceException if the corresponding ressource could not be found */ public synchronized void addHome(final @NotNull GNDMServiceHome home) throws ResourceException { if (home instanceof GNDMPersistentServiceHome<?>) addHome(((GNDMPersistentServiceHome<?>) home).getModelClass(), home); else addHome(null, home); } @SuppressWarnings({ "MethodWithTooExceptionsDeclared" }) @NotNull public AbstractORQCalculator<?, ?> newORQCalculator(final @NotNull EntityManagerFactory emf, final @NotNull String offerTypeKey) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { EntityManager em = emf.createEntityManager(); try { OfferType type = em.find(OfferType.class, offerTypeKey); if (type == null) throw new IllegalArgumentException("Unknow offer type: " + offerTypeKey); AbstractORQCalculator<?, ?> orqc = orqPark.getInstance(type); orqc.setConfigletProvider(this); return orqc; } finally { if (!em.isOpen()) em.close(); } } @SuppressWarnings({ "MethodWithTooExceptionsDeclared", "OverloadedMethodsWithSameNumberOfParameters" }) public TaskAction newTaskAction(final @NotNull EntityManagerFactory emf, final @NotNull String offerTypeKey) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { EntityManager em = emf.createEntityManager(); try { return newTaskAction(em, offerTypeKey); } finally { if (!em.isOpen()) em.close(); } } @SuppressWarnings({ "OverloadedMethodsWithSameNumberOfParameters" }) public TaskAction newTaskAction(final EntityManager emParam, final String offerTypeKey) throws IllegalAccessException, InstantiationException, ClassNotFoundException { OfferType type = emParam.find(OfferType.class, offerTypeKey); TaskAction ta = taskActionPark.getInstance(type); ta.setUUIDGen(uuidGen); return ta; } /** * Waits until an instance on {@link #instances} with the key <tt>name</tt>, has been registered and returns it. * * @param clazz the class the instance belongs to * @param name the name of the instance as denoted on the map {@link #instances} * @param <T> the class the instance will be casted to * @return an instance from the <tt>instances</tt> map */ public @NotNull <T> T waitForInstance(@NotNull Class<T> clazz, @NotNull String name) { T instance; try { instance = getInstance(clazz, name); } catch (IllegalStateException e) { instance = null; } while (instance != null) { try { Thread.sleep(INSTANCE_RETRIEVAL_INTERVAL); } catch (InterruptedException e) { // intended } try { instance = getInstance(clazz, name); } catch (IllegalStateException e) { instance = null; } } return instance; } /** * Adds the <tt>GNDMServiceHome</tt> and the corresponding <tt>org.globus.wsrf.Resource</tt> to the {@link #instances} map * and stores the key <tt>modelClazz</tt> with the value <tt>home</tt> to {@link #homes}. * * <p>The key for the <tt>GNDMServiceHome</tt> is the nickname of <tt>home</tt> appended by "HOME", whereas * the key for the Resource is the nickname of <tt>home</tt> appended by "Resource". * * @param modelClazz the class instance of the model * @param home a GNDMS Service resource home instance * @param <K> the specific subclass of the model instance * @throws ResourceException if the corresponding ressource could not be found */ @SuppressWarnings({ "HardcodedFileSeparator", "RawUseOfParameterizedType" }) public synchronized <K extends GridResource> void addHome(final Class<K> modelClazz, final @NotNull GNDMServiceHome home) throws ResourceException { if (homes.containsKey(modelClazz)) throw new IllegalStateException("Name clash in home registration"); else { final String homeName = home.getNickName() + "Home"; addInstance_(homeName, home); try { if (home instanceof GNDMSingletonServiceHome) { Object instance = home.find(null); final String resourceName = home.getNickName() + "Resource"; addInstance_(resourceName, instance); logger.debug(getSystemName() + " addSingletonResource: '" + resourceName + "' = '" + (modelClazz == null ? "(no model class)" : modelClazz.getName()) + '/' + ((GNDMSingletonServiceHome) home).getSingletonID() + '\''); } } catch (RuntimeException e) { instances.remove(homeName); throw e; } catch (ResourceException e) { instances.remove(homeName); throw e; } if (modelClazz != null) homes.put(modelClazz, (GNDMPersistentServiceHome<?>) home); } logger.debug(getSystemName() + " addHome: '" + home + '\''); } /** * Returns the GNDMPersistentServiceHome which is mapped by the key <tt>modelClazz</tt> in the map {@link #homes}. * * @param modelClazz the class of the model * @param <M> the specific class the model belongs to * @return */ @SuppressWarnings({ "unchecked" }) public synchronized <M extends GridResource> GNDMPersistentServiceHome<M> getHome(Class<M> modelClazz) { final GNDMPersistentServiceHome<M> home = (GNDMPersistentServiceHome<M>) homes.get(modelClazz); if (home == null) throw new IllegalStateException("Unknown home"); return home; } /* Adds an instance to the {@link #instances} map. * The name which will be mapped to the instance must not end with the keywords "HOME","Resource" or "ORQC". * * <p> Except them, there are more keywords which are not allowed. * See {@link #addInstance_ }, as this method will be invoked * * @param name the name which is to be mapped to the specified instance * @param obj the instance to be associated with the specified name */ public synchronized void addInstance(@NotNull String name, @NotNull Object obj) { if (name.endsWith("Home") || name.endsWith("Resource") || name.endsWith("ORQC")) throw new IllegalArgumentException("Reserved instance name"); addInstance_(name, obj); } /** * Adds an instance to the {@link #instances} map. * The name which will be mapped to the instance must not be equal to the keywords "out","err","args","em" or "emg". * * @param name the name which is to be mapped to the specified instance * @param obj the instance to be associated with the specified name */ private void addInstance_(final String name, final Object obj) { if ("out".equals(name) || "err".equals(name) || "args".equals(name) || "em".equals(name) || "emg".equals(name)) throw new IllegalArgumentException("Reserved instance name"); if (instances.containsKey(name)) throw new IllegalStateException("Name clash in instance registration: " + name); else instances.put(name, obj); logger.debug(getSystemName() + " addInstance: '" + name + '\''); } /** * Returns the instance, which has been registered on {@link #instances} with the name <tt>name</tt>. * The instace will be casted to the parameter <tt>T</tt> of <tt>clazz</tt>. * * @param clazz the class the instance belongs to * @param name the name of the instance as denoted on the map {@link #instances} * @param <T> the class the instance will be casted to * @return an instance from the <tt>instances</tt> map */ public synchronized @NotNull <T> T getInstance(@NotNull Class<? extends T> clazz, @NotNull String name) { final Object obj = instances.get(name); if (obj == null) throw new IllegalStateException("Null instance retrieved or invalid or unregistered name"); return clazz.cast(obj); } /** * Creates a new EntityManager using <tt>emf</tt>. * * <p>Calls {@link #loadConfigletStates(javax.persistence.EntityManager)} and * {@link #createOrUpdateConfiglets(de.zib.gndms.model.common.ConfigletState[])} to load all configlets managed by * this EntityManager and update the {@link #configlets} map. * Old Configlets will be removed and shutted down using {@link #shutdownConfiglets()} * * @param emf the factory the EntityManager will be created of */ public synchronized void reloadConfiglets(final EntityManagerFactory emf) { ConfigletState[] states; EntityManager em = emf.createEntityManager(); try { states = loadConfigletStates(em); createOrUpdateConfiglets(states); shutdownOldConfiglets(em); } finally { if (em.isOpen()) em.close(); } } /** * Loads all <tt>ConfigletStates</tt> managed by a specific <tt>EntityManager</tt> into an array. * * <p>Performs the query "listAllConfiglets" on the database and returns an array containing the result. * * @param emParam an EntityManager managing ConfigletStates * @return an array containing all ConfigletStates of the database */ @SuppressWarnings({ "unchecked", "JpaQueryApiInspection", "MethodMayBeStatic" }) private synchronized ConfigletState[] loadConfigletStates(final EntityManager emParam) { final ConfigletState[] states; emParam.getTransaction().begin(); try { Query query = emParam.createNamedQuery("listAllConfiglets"); final List<ConfigletState> list = (List<ConfigletState>) query.getResultList(); Object[] states_ = list.toArray(); states = new ConfigletState[states_.length]; for (int i = 0; i < states_.length; i++) states[i] = (ConfigletState) states_[i]; return states; } finally { if (emParam.getTransaction().isActive()) emParam.getTransaction().commit(); } } /** * Iterates through the <tt>ConfigletState</tt> array and either * updates the <tt>state</tt> of the corresponding <tt>Configlet</tt>, if already stored in the {@link #configlets} map, * or creates a new <tt>Configlet</tt> using {@link #createConfiglet(de.zib.gndms.model.common.ConfigletState)} * and stores it together with the name of the Configlet in the map. * * @param statesParam an array containing several ConfigletStates to be stored in the <tt>configlets</tt> map */ private synchronized void createOrUpdateConfiglets(final ConfigletState[] statesParam) { for (ConfigletState configletState : statesParam) { final String name = configletState.getName(); if (configlets.containsKey(name)) { configlets.get(name).update(configletState.getState()); } else { final Configlet configlet = createConfiglet(configletState); configlets.put(name, configlet); } } } /** * Creates a <tt>Configlet</tt> out of a ConfigletState. * * <p>The created instance uses {@link #logger} as its <tt>Log</tt> object. * The name and state of the new Configlet is taken from <tt>configParam</tt>. * * @param configParam A ConfigletState to be converted to a Configlet * * @return a Configlet out of a ConfigletState */ @SuppressWarnings({ "FeatureEnvy" }) private synchronized Configlet createConfiglet(final ConfigletState configParam) { try { final Class<? extends Configlet> clazz = Class.forName(configParam.getClassName()) .asSubclass(Configlet.class); final Configlet instance = clazz.newInstance(); instance.init(logger, configParam.getName(), configParam.getState()); return instance; } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } /** * Removes old configlets from the {@link #configlets} map. * * Checks for every <tt>Configlet</tt> in the map, if still exists in the database. * If not, the map entry will be removed and <tt>shutdown()</tt> invoked on the old configlet entry. * * @param emParam an EntityManager managing <tt>Configlet</tt>s */ @SuppressWarnings({ "SuspiciousMethodCalls" }) private synchronized void shutdownOldConfiglets(final EntityManager emParam) { Set<String> set = configlets.keySet(); Object[] keys = set.toArray(); for (Object name : keys) { emParam.getTransaction().begin(); try { if (emParam.find(ConfigletState.class, name) == null) { Configlet let = configlets.get(name); configlets.remove(name); let.shutdown(); } } catch (RuntimeException e) { logger.warn(e); } finally { if (emParam.getTransaction().isActive()) emParam.getTransaction().commit(); } } } /** * Shuts down all configlets stored in the {@link #configlets} map */ synchronized void shutdownConfiglets() { for (Configlet configlet : configlets.values()) try { configlet.shutdown(); } catch (RuntimeException e) { logger.warn(e); } } /** * Retrieves the configlet stored with the key <tt>name</tt> from {@link #configlets} map, casts it to a <tt>T</tt> class * and returns it. * * @param clazz the class the Configlet belongs to * @param name the name of the Configlet * @param <T> the class the instance will be casted to * @return a casted configlet from the <tt>configlets</tt> map */ public <T extends Configlet> T getConfiglet(final @NotNull Class<T> clazz, final @NotNull String name) { return clazz.cast(configlets.get(name)); } /** * Returns a <tt>GNDMServiceHome</tt> stored with a specif name in the {@link #instances} map. * * @param instancePrefix the prefix for the lookup key, which will be appended by "HOME" * @return */ public synchronized GNDMServiceHome lookupServiceHome(@NotNull String instancePrefix) { return getInstance(GNDMServiceHome.class, instancePrefix + "Home"); } public GroovyBindingFactory createBindingFactory() { return new GNDMSBindingFactory(); } public @NotNull String getSystemName() { return systemName; } /** * Returns the value set for the environment variable <tt>GNDMS_TMP</tt>. If nothing denoted, * it will return the value of the enviroment variable <tt>TMPDIR</tt> instead. * If also not denoted, "/tmp" will be returned. * * @return the temp directory of the GNDMSystem according to enviroment variables */ @NotNull @SuppressWarnings({ "HardcodedFileSeparator" }) public String getSystemTempDirName() { String tmp = System.getenv("GNDMS_TMP"); tmp = tmp == null ? "" : tmp.trim(); if (tmp.length() == 0) { tmp = System.getenv("TMPDIR"); tmp = tmp == null ? "" : tmp.trim(); } if (tmp.length() == 0) { tmp = "/tmp"; } return tmp; } /** * Binds certain classes to {@code this} or other corresponding instances * * @param binder binds several classe with certain fields. */ public void configure(final @NotNull Binder binder) { // binder.bind(EntityManagerFactory.class).toInstance(); binder.bind(BoundInjector.class).toInstance(boundInjector); binder.bind(SystemDirectory.class).toInstance(this); binder.bind(SystemInfo.class).toInstance(this); binder.bind(InstanceProvider.class).toInstance(this); binder.bind(ServiceHomeProvider.class).toInstance(this); binder.bind(TaskActionProvider.class).toInstance(this); binder.bind(ORQCalculatorProvider.class).toInstance(this); binder.bind(ConfigletProvider.class).toInstance(this); binder.bind(ModelUUIDGen.class).toInstance(uuidGen); } public final String DEFAULT_SUBGRID_NAME = "gndms"; @NotNull public String getSubGridName() { final DefaultConfiglet defaultConfiglet = getConfiglet(DefaultConfiglet.class, "gridconfig"); if (defaultConfiglet == null) return DEFAULT_SUBGRID_NAME; else return defaultConfiglet.getMapConfig().getOption("subGridName", DEFAULT_SUBGRID_NAME); } private final class GNDMSBindingFactory implements GroovyBindingFactory { public @NotNull Binding createBinding(final @NotNull GroovyMoniServer moniServer, final @NotNull Principal principal, final @NotNull String args) { final Binding binding = new Binding(); for (Map.Entry<String, Object> entry : instances.entrySet()) binding.setProperty(entry.getKey(), entry.getValue()); return binding; } @SuppressWarnings({ "StringBufferWithoutInitialCapacity" }) public void initShell(@NotNull GroovyShell shell, @NotNull Binding binding) { StringBuilder builder = new StringBuilder(); for (Map.Entry<String, Object> entry : instances.entrySet()) { final String key = entry.getKey(); builder.append("Object.metaClass."); builder.append(key); builder.append('='); builder.append(key); builder.append(';'); } shell.evaluate(builder.toString()); } public void destroyBinding(final @NotNull GroovyMoniServer moniServer, final @NotNull Binding binding) { // intended } } private static class OfferTypeIndustrialPark<T extends KeyFactoryInstance<OfferType, T>> extends IndustrialPark<OfferType, String, T> { private OfferTypeIndustrialPark( final @NotNull KeyFactory<OfferType, RecursiveKeyFactory<OfferType, T>> factoryParam) { super(factoryParam); } @NotNull @Override public String mapKey(final @NotNull OfferType keyParam) { return keyParam.getOfferTypeKey(); } } public @NotNull Injector getSystemAccessInjector() { return boundInjector.getInjector(); } }