| <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>IntakeServiceImpl.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Fulcrum Intake Service</a> > <a href="index.source.html" class="el_package">org.apache.fulcrum.intake</a> > <span class="el_source">IntakeServiceImpl.java</span></div><h1>IntakeServiceImpl.java</h1><pre class="source lang-java linenums">package org.apache.fulcrum.intake; |
| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF 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. |
| */ |
| |
| import java.beans.IntrospectionException; |
| import java.beans.PropertyDescriptor; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.ObjectInputStream; |
| import java.io.ObjectOutputStream; |
| import java.lang.reflect.Method; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.ListIterator; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Set; |
| |
| import javax.xml.XMLConstants; |
| import javax.xml.bind.JAXBContext; |
| import javax.xml.bind.Unmarshaller; |
| import javax.xml.bind.Unmarshaller.Listener; |
| import javax.xml.bind.helpers.DefaultValidationEventHandler; |
| import javax.xml.validation.SchemaFactory; |
| |
| import org.apache.avalon.framework.activity.Initializable; |
| import org.apache.avalon.framework.configuration.Configurable; |
| import org.apache.avalon.framework.configuration.Configuration; |
| import org.apache.avalon.framework.configuration.ConfigurationException; |
| import org.apache.avalon.framework.context.Context; |
| import org.apache.avalon.framework.context.ContextException; |
| import org.apache.avalon.framework.context.Contextualizable; |
| import org.apache.avalon.framework.logger.AbstractLogEnabled; |
| import org.apache.avalon.framework.logger.LogEnabled; |
| import org.apache.avalon.framework.service.ServiceException; |
| import org.apache.avalon.framework.service.ServiceManager; |
| import org.apache.avalon.framework.service.Serviceable; |
| import org.apache.commons.pool2.KeyedObjectPool; |
| import org.apache.commons.pool2.KeyedPooledObjectFactory; |
| import org.apache.commons.pool2.impl.GenericKeyedObjectPool; |
| import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig; |
| import org.apache.fulcrum.intake.model.AppData; |
| import org.apache.fulcrum.intake.model.Field; |
| import org.apache.fulcrum.intake.model.Group; |
| |
| /** |
| * This service provides access to input processing objects based on an XML |
| * specification. |
| * |
| * avalon.component name="intake" |
| * avalon.service type="org.apache.fulcrum.intake.IntakeService" |
| * |
| * @author <a href="mailto:jmcnally@collab.net">John McNally</a> |
| * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a> |
| * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a> |
| * @version $Id$ |
| */ |
| <span class="fc" id="L80">public class IntakeServiceImpl extends AbstractLogEnabled implements</span> |
| IntakeService, Configurable, Initializable, Contextualizable, |
| Serviceable |
| { |
| /** Map of groupNames -> appData elements */ |
| private Map<String, AppData> groupNames; |
| |
| /** The cache of group names. */ |
| private Map<String, String> groupNameMap; |
| |
| /** The cache of group keys. */ |
| private Map<String, String> groupKeyMap; |
| |
| /** The cache of property getters. */ |
| private Map<String, Map<String, Method>> getterMap; |
| |
| /** The cache of property setters. */ |
| private Map<String, Map<String, Method>> setterMap; |
| |
| /** AppData -> keyed Pools Map */ |
| private Map<AppData, KeyedObjectPool<String, Group>> keyedPools; |
| |
| /** The Avalon Container root directory */ |
| private String applicationRoot; |
| |
| /** List of configured xml specification files */ |
| <span class="fc" id="L106"> private List<String> xmlPathes = null;</span> |
| |
| /** Configured location of the serialization file */ |
| <span class="fc" id="L109"> private String serialDataPath = null;</span> |
| |
| /** |
| * Local Class to enable Avalon logging on the model classes |
| * |
| */ |
| <span class="fc" id="L115"> private class AvalonLogEnabledListener extends Listener</span> |
| { |
| /** |
| * @see javax.xml.bind.Unmarshaller.Listener#beforeUnmarshal(java.lang.Object, java.lang.Object) |
| */ |
| @Override |
| public void beforeUnmarshal(Object target, Object parent) |
| { |
| <span class="fc" id="L123"> super.beforeUnmarshal(target, parent);</span> |
| |
| <span class="fc bfc" id="L125" title="All 2 branches covered."> if (target instanceof LogEnabled)</span> |
| { |
| <span class="fc" id="L127"> ((LogEnabled)target).enableLogging(getLogger());</span> |
| } |
| <span class="fc" id="L129"> }</span> |
| |
| } |
| |
| /** |
| * Registers a given group name in the system |
| * |
| * @param groupName |
| * The name to register the group under |
| * @param group |
| * The Group to register in |
| * @param appData |
| * The app Data object where the group can be found |
| * @param checkKey |
| * Whether to check if the key also exists. |
| * |
| * @return true if successful, false if not |
| */ |
| private boolean registerGroup(String groupName, Group group, |
| AppData appData, boolean checkKey) |
| { |
| <span class="pc bpc" id="L150" title="1 of 2 branches missed."> if (groupNames.containsKey(groupName))</span> |
| { |
| // This name already exists. |
| <span class="nc" id="L153"> return false;</span> |
| } |
| |
| <span class="fc" id="L156"> boolean keyExists = groupNameMap.containsKey(group.getGID());</span> |
| |
| <span class="pc bpc" id="L158" title="2 of 4 branches missed."> if (checkKey && keyExists)</span> |
| { |
| // The key for this package is already registered for another group |
| <span class="nc" id="L161"> return false;</span> |
| } |
| |
| <span class="fc" id="L164"> groupNames.put(groupName, appData);</span> |
| <span class="fc" id="L165"> groupKeyMap.put(groupName, group.getGID());</span> |
| |
| <span class="pc bpc" id="L167" title="1 of 2 branches missed."> if (!keyExists)</span> |
| { |
| // This key does not exist. Add it to the hash. |
| <span class="fc" id="L170"> groupNameMap.put(group.getGID(), groupName);</span> |
| } |
| |
| <span class="fc" id="L173"> List<Field<?>> fields = group.getFields();</span> |
| <span class="fc bfc" id="L174" title="All 2 branches covered."> for (Field<?> field : fields)</span> |
| { |
| <span class="fc" id="L176"> String className = field.getMapToObject();</span> |
| <span class="fc bfc" id="L177" title="All 2 branches covered."> if (!getterMap.containsKey(className))</span> |
| { |
| <span class="fc" id="L179"> getterMap.put(className, new HashMap<String, Method>());</span> |
| <span class="fc" id="L180"> setterMap.put(className, new HashMap<String, Method>());</span> |
| } |
| <span class="fc" id="L182"> }</span> |
| <span class="fc" id="L183"> return true;</span> |
| } |
| |
| /** |
| * Tries to load a serialized Intake Group file. This can reduce the startup |
| * time of Turbine. |
| * |
| * @param serialDataPath |
| * The path of the File to load. |
| * |
| * @return A map with appData objects loaded from the file or null if the |
| * map could not be loaded. |
| */ |
| private Map<AppData, File> loadSerialized(String serialDataPath, long timeStamp) |
| { |
| <span class="fc" id="L198"> getLogger().debug(</span> |
| "Entered loadSerialized(" + serialDataPath + ", " + timeStamp |
| + ")"); |
| |
| <span class="fc" id="L202"> long timer = System.currentTimeMillis();</span> |
| |
| <span class="pc bpc" id="L204" title="1 of 2 branches missed."> if (serialDataPath == null)</span> |
| { |
| <span class="nc" id="L206"> return null;</span> |
| } |
| |
| <span class="fc" id="L209"> File serialDataFile = new File(serialDataPath);</span> |
| |
| <span class="fc bfc" id="L211" title="All 2 branches covered."> if (!serialDataFile.exists())</span> |
| { |
| <span class="fc" id="L213"> getLogger().info("No serialized file found, parsing XML");</span> |
| <span class="fc" id="L214"> return null;</span> |
| } |
| |
| <span class="pc bpc" id="L217" title="1 of 2 branches missed."> if (serialDataFile.lastModified() <= timeStamp)</span> |
| { |
| <span class="nc" id="L219"> getLogger().info("serialized file too old, parsing XML");</span> |
| <span class="nc" id="L220"> return null;</span> |
| } |
| |
| <span class="fc" id="L223"> ObjectInputStream in = null;</span> |
| <span class="fc" id="L224"> Map<AppData, File> serialData = null;</span> |
| |
| try |
| { |
| <span class="fc" id="L228"> FileInputStream fin = new FileInputStream(serialDataFile);</span> |
| <span class="fc" id="L229"> in = new ObjectInputStream(fin);</span> |
| <span class="fc" id="L230"> Object o = in.readObject();</span> |
| |
| <span class="pc bpc" id="L232" title="1 of 2 branches missed."> if (o instanceof Map)</span> |
| { |
| @SuppressWarnings("unchecked") // checked with instanceof |
| <span class="fc" id="L235"> Map<AppData, File> map = (Map<AppData, File>) o;</span> |
| <span class="fc" id="L236"> serialData = map;</span> |
| <span class="fc" id="L237"> }</span> |
| else |
| { |
| // This could be old file from intake. Try to delete it |
| <span class="nc" id="L241"> getLogger().info("serialized object is not an intake map, ignoring");</span> |
| <span class="nc" id="L242"> in.close();</span> |
| <span class="nc" id="L243"> in = null;</span> |
| |
| // Try to delete the file |
| <span class="nc" id="L246"> boolean result = serialDataFile.delete();</span> |
| <span class="nc bnc" id="L247" title="All 2 branches missed."> if ( result == false )</span> |
| { |
| <span class="nc" id="L249"> getLogger().error("Unknown serialized file could not be removed");</span> |
| } |
| } |
| } |
| <span class="nc" id="L253"> catch (IOException e)</span> |
| { |
| <span class="nc" id="L255"> getLogger().error("Serialized File could not be read.", e);</span> |
| |
| // We got a corrupt file for some reason. |
| // Null out serialData to be sure |
| <span class="nc" id="L259"> serialData = null;</span> |
| } |
| <span class="nc" id="L261"> catch (ClassNotFoundException e)</span> |
| { |
| <span class="nc" id="L263"> getLogger().error("Objects could not be read from serialized file.", e);</span> |
| |
| // This should not happen |
| // Null out serialData to be sure |
| <span class="nc" id="L267"> serialData = null;</span> |
| } |
| finally |
| { |
| // Could be null if we opened a file, didn't find it to be a |
| // Map object and then nuked it away. |
| try |
| { |
| <span class="pc bpc" id="L275" title="1 of 2 branches missed."> if (in != null)</span> |
| { |
| <span class="fc" id="L277"> in.close();</span> |
| } |
| } |
| <span class="nc" id="L280"> catch (IOException e)</span> |
| { |
| <span class="nc" id="L282"> getLogger().error("Exception while closing file", e);</span> |
| <span class="fc" id="L283"> }</span> |
| } |
| |
| // Recreate transient loggers |
| <span class="pc bpc" id="L287" title="1 of 2 branches missed."> if (serialData != null)</span> |
| { |
| <span class="fc bfc" id="L289" title="All 2 branches covered."> for (AppData appData : serialData.keySet())</span> |
| { |
| <span class="fc bfc" id="L291" title="All 2 branches covered."> for (Group group : appData.getGroups())</span> |
| { |
| <span class="pc bpc" id="L293" title="1 of 2 branches missed."> if (group instanceof LogEnabled)</span> |
| { |
| <span class="fc" id="L295"> ((LogEnabled)group).enableLogging(getLogger());</span> |
| } |
| |
| <span class="fc bfc" id="L298" title="All 2 branches covered."> for (Field<?> field : group.getFields())</span> |
| { |
| <span class="pc bpc" id="L300" title="1 of 2 branches missed."> if (field instanceof LogEnabled)</span> |
| { |
| <span class="fc" id="L302"> ((LogEnabled)field).enableLogging(getLogger());</span> |
| } |
| <span class="fc" id="L304"> }</span> |
| <span class="fc" id="L305"> }</span> |
| <span class="fc" id="L306"> }</span> |
| } |
| <span class="fc" id="L308"> getLogger().info("Loaded serialized map object, ignoring XML");</span> |
| <span class="fc" id="L309"> getLogger().debug("Loading took " + (System.currentTimeMillis() - timer));</span> |
| <span class="fc" id="L310"> return serialData;</span> |
| } |
| |
| /** |
| * Writes a parsed XML map with all the appData groups into a file. This |
| * will speed up loading time when you restart the Intake Service because it |
| * will only unserialize this file instead of reloading all of the XML files |
| * |
| * @param serialDataPath |
| * The path of the file to write to |
| * @param appDataElements |
| * A Map containing all of the XML parsed appdata elements |
| */ |
| private void saveSerialized(String serialDataPath, Map<AppData, File> appDataElements) |
| { |
| |
| <span class="fc" id="L326"> getLogger().debug(</span> |
| "Entered saveSerialized(" + serialDataPath |
| + ", appDataElements)"); |
| |
| <span class="fc" id="L330"> long timer = System.currentTimeMillis();</span> |
| |
| <span class="pc bpc" id="L332" title="1 of 2 branches missed."> if (serialDataPath == null)</span> |
| { |
| <span class="nc" id="L334"> return;</span> |
| } |
| |
| <span class="fc" id="L337"> File serialData = new File(serialDataPath);</span> |
| |
| try |
| { |
| <span class="fc" id="L341"> boolean result = serialData.createNewFile();</span> |
| <span class="pc bpc" id="L342" title="1 of 2 branches missed."> if ( result == false )</span> |
| { |
| <span class="nc" id="L344"> getLogger().error("Could not create new serialized file");</span> |
| } |
| |
| // Try to delete the file |
| <span class="fc" id="L348"> result = serialData.delete();</span> |
| <span class="pc bpc" id="L349" title="1 of 2 branches missed."> if ( result == false )</span> |
| { |
| <span class="nc" id="L351"> getLogger().error("Serialized file could not be removed");</span> |
| } |
| |
| } |
| <span class="nc" id="L355"> catch (IOException e)</span> |
| { |
| <span class="nc" id="L357"> getLogger().info(</span> |
| "Could not create serialized file " + serialDataPath |
| + ", not serializing the XML data", e); |
| <span class="nc" id="L360"> return;</span> |
| <span class="fc" id="L361"> }</span> |
| |
| <span class="fc" id="L363"> ObjectOutputStream out = null;</span> |
| <span class="fc" id="L364"> ObjectInputStream in = null;</span> |
| |
| try |
| { |
| // write the appData file out |
| <span class="fc" id="L369"> FileOutputStream fout = new FileOutputStream(serialDataPath);</span> |
| <span class="fc" id="L370"> out = new ObjectOutputStream(fout);</span> |
| <span class="fc" id="L371"> out.writeObject(appDataElements);</span> |
| <span class="fc" id="L372"> out.flush();</span> |
| |
| // read the file back in. for some reason on OSX 10.1 |
| // this is necessary. |
| <span class="fc" id="L376"> FileInputStream fin = new FileInputStream(serialDataPath);</span> |
| <span class="fc" id="L377"> in = new ObjectInputStream(fin);</span> |
| <span class="fc" id="L378"> /* Map dummy = (Map) */ in.readObject();</span> |
| |
| <span class="fc" id="L380"> getLogger().debug("Serializing successful");</span> |
| } |
| <span class="nc" id="L382"> catch (IOException e)</span> |
| { |
| <span class="nc" id="L384"> getLogger().info(</span> |
| "Could not write serialized file to " + serialDataPath |
| + ", not serializing the XML data", e); |
| } |
| <span class="nc" id="L388"> catch (ClassNotFoundException e)</span> |
| { |
| <span class="nc" id="L390"> getLogger().info(</span> |
| "Could not re-read serialized file from " + serialDataPath, e); |
| } |
| finally |
| { |
| try |
| { |
| <span class="pc bpc" id="L397" title="1 of 2 branches missed."> if (out != null)</span> |
| { |
| <span class="fc" id="L399"> out.close();</span> |
| } |
| } |
| <span class="nc" id="L402"> catch (IOException e)</span> |
| { |
| <span class="nc" id="L404"> getLogger().error("Exception while closing file", e);</span> |
| <span class="fc" id="L405"> }</span> |
| try |
| { |
| <span class="pc bpc" id="L408" title="1 of 2 branches missed."> if (in != null)</span> |
| { |
| <span class="fc" id="L410"> in.close();</span> |
| } |
| } |
| <span class="nc" id="L413"> catch (IOException e)</span> |
| { |
| <span class="nc" id="L415"> getLogger().error("Exception while closing file", e);</span> |
| <span class="fc" id="L416"> }</span> |
| } |
| |
| <span class="fc" id="L419"> getLogger().debug("Saving took " + (System.currentTimeMillis() - timer));</span> |
| <span class="fc" id="L420"> }</span> |
| |
| /** |
| * Gets an instance of a named group either from the pool or by calling the |
| * Factory Service if the pool is empty. |
| * |
| * @param groupName |
| * the name of the group. |
| * @return a Group instance. |
| * @throws IntakeException |
| * if recycling fails. |
| */ |
| @Override |
| public Group getGroup(String groupName) throws IntakeException |
| { |
| <span class="fc" id="L435"> Group group = null;</span> |
| |
| <span class="fc" id="L437"> AppData appData = groupNames.get(groupName);</span> |
| |
| <span class="pc bpc" id="L439" title="1 of 2 branches missed."> if (groupName == null)</span> |
| { |
| <span class="nc" id="L441"> throw new IntakeException(</span> |
| "Intake IntakeServiceImpl.getGroup(groupName) is null"); |
| } |
| |
| <span class="pc bpc" id="L445" title="1 of 2 branches missed."> if (appData == null)</span> |
| { |
| <span class="nc" id="L447"> throw new IntakeException(</span> |
| "Intake IntakeServiceImpl.getGroup(groupName): No XML definition for Group " |
| + groupName + " found"); |
| } |
| try |
| { |
| <span class="fc" id="L453"> group = keyedPools.get(appData).borrowObject(groupName);</span> |
| } |
| <span class="nc" id="L455"> catch (Exception e)</span> |
| { |
| <span class="nc" id="L457"> throw new IntakeException("Could not get group " + groupName, e);</span> |
| <span class="fc" id="L458"> }</span> |
| <span class="fc" id="L459"> return group;</span> |
| } |
| |
| /** |
| * Puts a Group back to the pool. |
| * |
| * @param instance |
| * the object instance to recycle. |
| * |
| * @throws IntakeException |
| * The passed group name does not exist. |
| */ |
| @Override |
| public void releaseGroup(Group instance) throws IntakeException |
| { |
| <span class="nc bnc" id="L474" title="All 2 branches missed."> if (instance != null)</span> |
| { |
| <span class="nc" id="L476"> String groupName = instance.getIntakeGroupName();</span> |
| <span class="nc" id="L477"> AppData appData = groupNames.get(groupName);</span> |
| |
| <span class="nc bnc" id="L479" title="All 2 branches missed."> if (appData == null)</span> |
| { |
| <span class="nc" id="L481"> throw new IntakeException(</span> |
| "Intake IntakeServiceImpl.releaseGroup(groupName): " |
| + "No XML definition for Group " + groupName |
| + " found"); |
| } |
| |
| try |
| { |
| <span class="nc" id="L489"> keyedPools.get(appData).returnObject(groupName, instance);</span> |
| } |
| <span class="nc" id="L491"> catch (Exception e)</span> |
| { |
| <span class="nc" id="L493"> throw new IntakeException("Could not get group " + groupName, e);</span> |
| <span class="nc" id="L494"> }</span> |
| } |
| <span class="nc" id="L496"> }</span> |
| |
| /** |
| * Gets the current size of the pool for a group. |
| * |
| * @param groupName |
| * the name of the group. |
| * |
| * @throws IntakeException |
| * The passed group name does not exist. |
| */ |
| @Override |
| public int getSize(String groupName) throws IntakeException |
| { |
| <span class="nc" id="L510"> AppData appData = groupNames.get(groupName);</span> |
| <span class="nc bnc" id="L511" title="All 2 branches missed."> if (appData == null)</span> |
| { |
| <span class="nc" id="L513"> throw new IntakeException(</span> |
| "Intake IntakeServiceImpl.Size(groupName): No XML definition for Group " |
| + groupName + " found"); |
| } |
| |
| <span class="nc" id="L518"> KeyedObjectPool<String, Group> kop = keyedPools.get(appData);</span> |
| |
| <span class="nc" id="L520"> return kop.getNumActive(groupName) + kop.getNumIdle(groupName);</span> |
| } |
| |
| /** |
| * Names of all the defined groups. |
| * |
| * @return array of names. |
| */ |
| @Override |
| public String[] getGroupNames() |
| { |
| <span class="nc" id="L531"> return groupNames.keySet().toArray(new String[0]);</span> |
| } |
| |
| /** |
| * Gets the key (usually a short identifier) for a group. |
| * |
| * @param groupName |
| * the name of the group. |
| * @return the the key. |
| */ |
| @Override |
| public String getGroupKey(String groupName) |
| { |
| <span class="nc" id="L544"> return groupKeyMap.get(groupName);</span> |
| } |
| |
| /** |
| * Gets the group name given its key. |
| * |
| * @param groupKey |
| * the key. |
| * @return groupName the name of the group. |
| */ |
| @Override |
| public String getGroupName(String groupKey) |
| { |
| <span class="nc" id="L557"> return groupNameMap.get(groupKey);</span> |
| } |
| |
| /** |
| * Gets the Method that can be used to set a property. |
| * |
| * @param className |
| * the name of the object. |
| * @param propName |
| * the name of the property. |
| * @return the setter. |
| * @throws ClassNotFoundException if the class specified could not be loaded |
| * @throws IntrospectionException if the property setter could not be called |
| */ |
| @Override |
| public Method getFieldSetter(String className, String propName) |
| throws ClassNotFoundException, IntrospectionException |
| { |
| <span class="fc" id="L575"> Map<String, Method> settersForClassName = setterMap.get(className);</span> |
| |
| <span class="pc bpc" id="L577" title="1 of 2 branches missed."> if (settersForClassName == null)</span> |
| { |
| <span class="nc" id="L579"> throw new IntrospectionException("No setter Map for " + className</span> |
| + " available!"); |
| } |
| |
| <span class="fc" id="L583"> Method setter = settersForClassName.get(propName);</span> |
| |
| <span class="pc bpc" id="L585" title="1 of 2 branches missed."> if (setter == null)</span> |
| { |
| <span class="fc" id="L587"> PropertyDescriptor pd = new PropertyDescriptor(propName, Class</span> |
| <span class="fc" id="L588"> .forName(className));</span> |
| <span class="fc" id="L589"> synchronized (setterMap)</span> |
| { |
| <span class="fc" id="L591"> setter = pd.getWriteMethod();</span> |
| <span class="fc" id="L592"> settersForClassName.put(propName, setter);</span> |
| <span class="pc bpc" id="L593" title="1 of 2 branches missed."> if (setter == null)</span> |
| { |
| <span class="nc" id="L595"> getLogger().error(</span> |
| "Intake: setter for '" + propName + "' in class '" |
| + className + "' could not be found."); |
| } |
| <span class="fc" id="L599"> }</span> |
| // we have already completed the reflection on the getter, so |
| // save it so we do not have to repeat |
| <span class="fc" id="L602"> synchronized (getterMap)</span> |
| { |
| <span class="fc" id="L604"> Map<String, Method> gettersForClassName = getterMap.get(className);</span> |
| |
| <span class="pc bpc" id="L606" title="1 of 2 branches missed."> if (gettersForClassName != null)</span> |
| { |
| <span class="fc" id="L608"> Method getter = pd.getReadMethod();</span> |
| <span class="pc bpc" id="L609" title="1 of 2 branches missed."> if (getter != null)</span> |
| { |
| <span class="fc" id="L611"> gettersForClassName.put(propName, getter);</span> |
| } |
| } |
| <span class="fc" id="L614"> }</span> |
| } |
| <span class="fc" id="L616"> return setter;</span> |
| } |
| |
| /** |
| * Gets the Method that can be used to get a property value. |
| * |
| * @param className |
| * the name of the object. |
| * @param propName |
| * the name of the property. |
| * @return the getter. |
| * @throws ClassNotFoundException if the class specified could not be loaded |
| * @throws IntrospectionException if the property getter could not be called |
| */ |
| @Override |
| public Method getFieldGetter(String className, String propName) |
| throws ClassNotFoundException, IntrospectionException |
| { |
| <span class="fc" id="L634"> Map<String, Method> gettersForClassName = getterMap.get(className);</span> |
| |
| <span class="pc bpc" id="L636" title="1 of 2 branches missed."> if (gettersForClassName == null)</span> |
| { |
| <span class="nc" id="L638"> throw new IntrospectionException("No getter Map for " + className</span> |
| + " available!"); |
| } |
| |
| <span class="fc" id="L642"> Method getter = gettersForClassName.get(propName);</span> |
| |
| <span class="pc bpc" id="L644" title="1 of 2 branches missed."> if (getter == null)</span> |
| { |
| <span class="fc" id="L646"> PropertyDescriptor pd = null;</span> |
| <span class="fc" id="L647"> synchronized (getterMap)</span> |
| { |
| <span class="fc" id="L649"> pd = new PropertyDescriptor(propName, Class.forName(className));</span> |
| <span class="fc" id="L650"> getter = pd.getReadMethod();</span> |
| <span class="fc" id="L651"> gettersForClassName.put(propName, getter);</span> |
| <span class="pc bpc" id="L652" title="1 of 2 branches missed."> if (getter == null)</span> |
| { |
| <span class="nc" id="L654"> getLogger().error(</span> |
| "Intake: getter for '" + propName + "' in class '" |
| + className + "' could not be found."); |
| } |
| <span class="fc" id="L658"> }</span> |
| // we have already completed the reflection on the setter, so |
| // save it so we do not have to repeat |
| <span class="fc" id="L661"> synchronized (setterMap)</span> |
| { |
| <span class="fc" id="L663"> Map<String, Method> settersForClassName = getterMap.get(className);</span> |
| |
| <span class="pc bpc" id="L665" title="1 of 2 branches missed."> if (settersForClassName != null)</span> |
| { |
| <span class="fc" id="L667"> Method setter = pd.getWriteMethod();</span> |
| <span class="pc bpc" id="L668" title="1 of 2 branches missed."> if (setter != null)</span> |
| { |
| <span class="fc" id="L670"> settersForClassName.put(propName, setter);</span> |
| } |
| } |
| <span class="fc" id="L673"> }</span> |
| } |
| <span class="fc" id="L675"> return getter;</span> |
| } |
| |
| // ---------------- Avalon Lifecycle Methods --------------------- |
| /** |
| * Avalon component lifecycle method |
| */ |
| @Override |
| public void configure(Configuration conf) throws ConfigurationException |
| { |
| <span class="fc" id="L685"> final Configuration xmlPaths = conf.getChild(XML_PATHS, false);</span> |
| |
| <span class="fc" id="L687"> xmlPathes = new ArrayList<String>();</span> |
| |
| <span class="pc bpc" id="L689" title="1 of 2 branches missed."> if (xmlPaths == null)</span> |
| { |
| <span class="nc" id="L691"> xmlPathes.add(XML_PATH_DEFAULT);</span> |
| } |
| else |
| { |
| <span class="fc" id="L695"> Configuration[] nameVal = xmlPaths.getChildren();</span> |
| <span class="fc bfc" id="L696" title="All 2 branches covered."> for (int i = 0; i < nameVal.length; i++)</span> |
| { |
| <span class="fc" id="L698"> String val = nameVal[i].getValue();</span> |
| <span class="fc" id="L699"> xmlPathes.add(val);</span> |
| } |
| } |
| |
| <span class="fc" id="L703"> serialDataPath = conf.getChild(SERIAL_XML, false).getValue(SERIAL_XML_DEFAULT);</span> |
| |
| <span class="pc bpc" id="L705" title="1 of 2 branches missed."> if (!serialDataPath.equalsIgnoreCase("none"))</span> |
| { |
| <span class="fc" id="L707"> serialDataPath = new File(applicationRoot, serialDataPath).getAbsolutePath();</span> |
| } |
| else |
| { |
| <span class="nc" id="L711"> serialDataPath = null;</span> |
| } |
| |
| <span class="fc" id="L714"> getLogger().debug("Path for serializing: " + serialDataPath);</span> |
| <span class="fc" id="L715"> }</span> |
| |
| /** |
| * Avalon component lifecycle method Initializes the service by loading |
| * xml rule files and creating the Intake groups. |
| * |
| * @throws Exception |
| * if initialization fails. |
| */ |
| @Override |
| public void initialize() throws Exception |
| { |
| <span class="fc" id="L727"> Map<AppData, File> appDataElements = null;</span> |
| |
| <span class="fc" id="L729"> groupNames = new HashMap<String, AppData>();</span> |
| <span class="fc" id="L730"> groupKeyMap = new HashMap<String, String>();</span> |
| <span class="fc" id="L731"> groupNameMap = new HashMap<String, String>();</span> |
| <span class="fc" id="L732"> getterMap = new HashMap<String, Map<String,Method>>();</span> |
| <span class="fc" id="L733"> setterMap = new HashMap<String, Map<String,Method>>();</span> |
| <span class="fc" id="L734"> keyedPools = new HashMap<AppData, KeyedObjectPool<String, Group>>();</span> |
| |
| <span class="fc" id="L736"> Set<File> xmlFiles = new HashSet<File>();</span> |
| |
| <span class="fc" id="L738"> long timeStamp = 0;</span> |
| |
| <span class="fc" id="L740"> getLogger().debug("logger is " + getLogger().getClass().getSimpleName());</span> |
| |
| <span class="fc bfc" id="L742" title="All 2 branches covered."> for (String xmlPath : xmlPathes)</span> |
| { |
| // Files are webapp.root relative |
| <span class="fc" id="L745"> File xmlFile = new File(applicationRoot, xmlPath).getAbsoluteFile();</span> |
| |
| <span class="fc" id="L747"> getLogger().debug("Path for XML File: " + xmlFile);</span> |
| |
| <span class="pc bpc" id="L749" title="1 of 2 branches missed."> if (!xmlFile.canRead())</span> |
| { |
| <span class="nc" id="L751"> String READ_ERR = "Could not read input file with path "</span> |
| + xmlPath + ". Looking for file " + xmlFile; |
| |
| <span class="nc" id="L754"> getLogger().error(READ_ERR);</span> |
| <span class="nc" id="L755"> throw new Exception(READ_ERR);</span> |
| } |
| |
| <span class="fc" id="L758"> xmlFiles.add(xmlFile);</span> |
| |
| <span class="fc" id="L760"> getLogger().debug("Added " + xmlPath + " as File to parse");</span> |
| |
| // Get the timestamp of the youngest file to be compared with |
| // a serialized file. If it is younger than the serialized file, |
| // then we have to parse the XML anyway. |
| <span class="pc bpc" id="L765" title="1 of 2 branches missed."> timeStamp = xmlFile.lastModified() > timeStamp ? xmlFile</span> |
| <span class="pc" id="L766"> .lastModified() : timeStamp;</span> |
| <span class="fc" id="L767"> }</span> |
| |
| <span class="fc" id="L769"> Map<AppData, File> serializedMap = loadSerialized(serialDataPath, timeStamp);</span> |
| |
| <span class="fc bfc" id="L771" title="All 2 branches covered."> if (serializedMap != null)</span> |
| { |
| // Use the serialized data as XML groups. Don't parse. |
| <span class="fc" id="L774"> appDataElements = serializedMap;</span> |
| <span class="fc" id="L775"> getLogger().debug("Using the serialized map");</span> |
| } |
| else |
| { |
| <span class="fc" id="L779"> long timer = System.currentTimeMillis();</span> |
| |
| // Parse all the given XML files |
| <span class="fc" id="L782"> JAXBContext jaxb = JAXBContext.newInstance(AppData.class);</span> |
| <span class="fc" id="L783"> Unmarshaller um = jaxb.createUnmarshaller();</span> |
| |
| // Debug mapping |
| <span class="fc" id="L786"> um.setEventHandler(new DefaultValidationEventHandler());</span> |
| |
| // Enable logging |
| <span class="fc" id="L789"> Listener logEnabledListener = new AvalonLogEnabledListener();</span> |
| <span class="fc" id="L790"> um.setListener(logEnabledListener);</span> |
| |
| <span class="fc" id="L792"> URL schemaURL = getClass().getResource("/intake.xsd");</span> |
| <span class="fc" id="L793"> SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);</span> |
| <span class="fc" id="L794"> um.setSchema(schemaFactory.newSchema(schemaURL));</span> |
| <span class="fc" id="L795"> appDataElements = new HashMap<AppData, File>();</span> |
| |
| <span class="fc bfc" id="L797" title="All 2 branches covered."> for (File xmlFile : xmlFiles)</span> |
| { |
| <span class="fc" id="L799"> getLogger().debug("Now parsing: " + xmlFile);</span> |
| <span class="fc" id="L800"> FileInputStream fis = null;</span> |
| try |
| { |
| <span class="fc" id="L803"> fis = new FileInputStream(xmlFile);</span> |
| <span class="fc" id="L804"> AppData appData = (AppData) um.unmarshal(fis);</span> |
| |
| <span class="fc" id="L806"> appDataElements.put(appData, xmlFile);</span> |
| <span class="fc" id="L807"> getLogger().debug("Saving AppData for " + xmlFile);</span> |
| } |
| finally |
| { |
| <span class="pc bpc" id="L811" title="1 of 2 branches missed."> if (fis != null)</span> |
| { |
| try |
| { |
| <span class="fc" id="L815"> fis.close();</span> |
| } |
| <span class="nc" id="L817"> catch (IOException e)</span> |
| { |
| <span class="nc" id="L819"> getLogger().warn("Could not close file " + xmlFile);</span> |
| <span class="fc" id="L820"> }</span> |
| } |
| } |
| <span class="fc" id="L823"> }</span> |
| |
| <span class="fc" id="L825"> getLogger().debug("Parsing took " + (System.currentTimeMillis() - timer));</span> |
| <span class="fc" id="L826"> saveSerialized(serialDataPath, appDataElements);</span> |
| } |
| |
| <span class="fc" id="L829"> int counter = 0;</span> |
| AppData appData; |
| File dataFile; |
| <span class="fc bfc" id="L832" title="All 2 branches covered."> for ( Entry<AppData, File> entry : appDataElements.entrySet() )</span> |
| { |
| // Set the entry pair |
| <span class="fc" id="L835"> appData = entry.getKey();</span> |
| <span class="fc" id="L836"> dataFile = entry.getValue();</span> |
| |
| <span class="fc" id="L838"> int maxPooledGroups = 0;</span> |
| <span class="fc" id="L839"> List<Group> glist = appData.getGroups();</span> |
| |
| <span class="fc" id="L841"> String groupPrefix = appData.getGroupPrefix();</span> |
| |
| <span class="fc bfc" id="L843" title="All 2 branches covered."> for (ListIterator<Group> i = glist.listIterator(glist.size()); i.hasPrevious();)</span> |
| { |
| <span class="fc" id="L845"> Group g = i.previous();</span> |
| <span class="fc" id="L846"> String groupName = g.getIntakeGroupName();</span> |
| |
| <span class="fc" id="L848"> boolean registerUnqualified = registerGroup(groupName, g, appData, true);</span> |
| |
| <span class="pc bpc" id="L850" title="1 of 2 branches missed."> if (!registerUnqualified)</span> |
| { |
| <span class="nc" id="L852"> getLogger().info(</span> |
| "Ignored redefinition of Group " + groupName |
| <span class="nc" id="L854"> + " or Key " + g.getGID() + " from "</span> |
| + dataFile); |
| } |
| |
| <span class="pc bpc" id="L858" title="1 of 2 branches missed."> if (groupPrefix != null)</span> |
| { |
| <span class="nc" id="L860"> StringBuilder qualifiedName = new StringBuilder();</span> |
| <span class="nc" id="L861"> qualifiedName.append(groupPrefix).append(':').append(groupName);</span> |
| |
| // Add the fully qualified group name. Do _not_ check |
| // for |
| // the existence of the key if the unqualified |
| // registration succeeded |
| // (because then it was added by the registerGroup |
| // above). |
| <span class="nc bnc" id="L869" title="All 4 branches missed."> if (!registerGroup(qualifiedName.toString(), g,</span> |
| appData, !registerUnqualified)) |
| { |
| <span class="nc" id="L872"> getLogger().error(</span> |
| "Could not register fully qualified name " |
| + qualifiedName |
| + ", maybe two XML files have the same prefix. Ignoring it."); |
| } |
| } |
| |
| // Init fields |
| <span class="fc bfc" id="L880" title="All 2 branches covered."> for (Field<?> f : g.getFields())</span> |
| { |
| <span class="fc" id="L882"> f.initGetterAndSetter();</span> |
| <span class="fc" id="L883"> }</span> |
| |
| <span class="fc" id="L885"> maxPooledGroups = Math.max(maxPooledGroups, g.getPoolCapacity());</span> |
| <span class="fc" id="L886"> }</span> |
| |
| <span class="fc" id="L888"> KeyedPooledObjectFactory<String, Group> factory =</span> |
| new Group.GroupFactory(appData); |
| |
| <span class="fc" id="L891"> GenericKeyedObjectPoolConfig<Group> poolConfig = new GenericKeyedObjectPoolConfig<Group>();</span> |
| <span class="fc" id="L892"> poolConfig.setMaxTotalPerKey(maxPooledGroups);</span> |
| <span class="fc" id="L893"> poolConfig.setJmxEnabled(true);</span> |
| <span class="fc" id="L894"> poolConfig.setJmxNamePrefix("fulcrum-intake-pool-" + counter++);</span> |
| |
| <span class="fc" id="L896"> keyedPools.put(appData,</span> |
| new GenericKeyedObjectPool<String, Group>(factory, poolConfig)); |
| <span class="fc" id="L898"> }</span> |
| |
| <span class="pc bpc" id="L900" title="1 of 2 branches missed."> if (getLogger().isInfoEnabled())</span> |
| { |
| <span class="fc" id="L902"> getLogger().info("Intake Service is initialized now.");</span> |
| } |
| <span class="fc" id="L904"> }</span> |
| |
| /** |
| * Note that the avalon.entry key="urn:avalon:home" |
| * and the type is {@link java.io.File} |
| * |
| * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context) |
| * |
| * @param context the Context to use |
| * @throws ContextException if the context is not found |
| */ |
| @Override |
| public void contextualize(Context context) throws ContextException |
| { |
| <span class="fc" id="L918"> this.applicationRoot = context.get("urn:avalon:home").toString();</span> |
| <span class="fc" id="L919"> }</span> |
| |
| /** |
| * Avalon component lifecycle method |
| * |
| * avalon.dependency type="org.apache.fulcrum.localization.LocalizationService" |
| * |
| * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager) |
| * |
| * @param manager the service manager |
| * @throws ServiceException generic exception |
| */ |
| @Override |
| public void service(ServiceManager manager) throws ServiceException |
| { |
| <span class="fc" id="L934"> IntakeServiceFacade.setIntakeService(this);</span> |
| <span class="fc" id="L935"> }</span> |
| } |
| </pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.6.202009150832</span></div></body></html> |