blob: e95ff877c99977fb1fd95072d2c3cbe56771f934 [file] [log] [blame]
<?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> &gt; <a href="index.source.html" class="el_package">org.apache.fulcrum.intake</a> &gt; <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
* &quot;License&quot;); 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
* &quot;AS IS&quot; 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=&quot;intake&quot;
* avalon.service type=&quot;org.apache.fulcrum.intake.IntakeService&quot;
*
* @author &lt;a href=&quot;mailto:jmcnally@collab.net&quot;&gt;John McNally&lt;/a&gt;
* @author &lt;a href=&quot;mailto:hps@intermeta.de&quot;&gt;Henning P. Schmiedehausen&lt;/a&gt;
* @author &lt;a href=&quot;mailto:quintonm@bellsouth.net&quot;&gt;Quinton McCombs&lt;/a&gt;
* @version $Id$
*/
<span class="fc" id="L80">public class IntakeServiceImpl extends AbstractLogEnabled implements</span>
IntakeService, Configurable, Initializable, Contextualizable,
Serviceable
{
/** Map of groupNames -&gt; appData elements */
private Map&lt;String, AppData&gt; groupNames;
/** The cache of group names. */
private Map&lt;String, String&gt; groupNameMap;
/** The cache of group keys. */
private Map&lt;String, String&gt; groupKeyMap;
/** The cache of property getters. */
private Map&lt;String, Map&lt;String, Method&gt;&gt; getterMap;
/** The cache of property setters. */
private Map&lt;String, Map&lt;String, Method&gt;&gt; setterMap;
/** AppData -&gt; keyed Pools Map */
private Map&lt;AppData, KeyedObjectPool&lt;String, Group&gt;&gt; keyedPools;
/** The Avalon Container root directory */
private String applicationRoot;
/** List of configured xml specification files */
<span class="fc" id="L106"> private List&lt;String&gt; 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 &amp;&amp; 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&lt;Field&lt;?&gt;&gt; fields = group.getFields();</span>
<span class="fc bfc" id="L174" title="All 2 branches covered."> for (Field&lt;?&gt; 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&lt;String, Method&gt;());</span>
<span class="fc" id="L180"> setterMap.put(className, new HashMap&lt;String, Method&gt;());</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&lt;AppData, File&gt; loadSerialized(String serialDataPath, long timeStamp)
{
<span class="fc" id="L198"> getLogger().debug(</span>
&quot;Entered loadSerialized(&quot; + serialDataPath + &quot;, &quot; + timeStamp
+ &quot;)&quot;);
<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(&quot;No serialized file found, parsing XML&quot;);</span>
<span class="fc" id="L214"> return null;</span>
}
<span class="pc bpc" id="L217" title="1 of 2 branches missed."> if (serialDataFile.lastModified() &lt;= timeStamp)</span>
{
<span class="nc" id="L219"> getLogger().info(&quot;serialized file too old, parsing XML&quot;);</span>
<span class="nc" id="L220"> return null;</span>
}
<span class="fc" id="L223"> ObjectInputStream in = null;</span>
<span class="fc" id="L224"> Map&lt;AppData, File&gt; 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(&quot;unchecked&quot;) // checked with instanceof
<span class="fc" id="L235"> Map&lt;AppData, File&gt; map = (Map&lt;AppData, File&gt;) 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(&quot;serialized object is not an intake map, ignoring&quot;);</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(&quot;Unknown serialized file could not be removed&quot;);</span>
}
}
}
<span class="nc" id="L253"> catch (IOException e)</span>
{
<span class="nc" id="L255"> getLogger().error(&quot;Serialized File could not be read.&quot;, 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(&quot;Objects could not be read from serialized file.&quot;, 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(&quot;Exception while closing file&quot;, 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&lt;?&gt; 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(&quot;Loaded serialized map object, ignoring XML&quot;);</span>
<span class="fc" id="L309"> getLogger().debug(&quot;Loading took &quot; + (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&lt;AppData, File&gt; appDataElements)
{
<span class="fc" id="L326"> getLogger().debug(</span>
&quot;Entered saveSerialized(&quot; + serialDataPath
+ &quot;, appDataElements)&quot;);
<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(&quot;Could not create new serialized file&quot;);</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(&quot;Serialized file could not be removed&quot;);</span>
}
}
<span class="nc" id="L355"> catch (IOException e)</span>
{
<span class="nc" id="L357"> getLogger().info(</span>
&quot;Could not create serialized file &quot; + serialDataPath
+ &quot;, not serializing the XML data&quot;, 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(&quot;Serializing successful&quot;);</span>
}
<span class="nc" id="L382"> catch (IOException e)</span>
{
<span class="nc" id="L384"> getLogger().info(</span>
&quot;Could not write serialized file to &quot; + serialDataPath
+ &quot;, not serializing the XML data&quot;, e);
}
<span class="nc" id="L388"> catch (ClassNotFoundException e)</span>
{
<span class="nc" id="L390"> getLogger().info(</span>
&quot;Could not re-read serialized file from &quot; + 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(&quot;Exception while closing file&quot;, 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(&quot;Exception while closing file&quot;, e);</span>
<span class="fc" id="L416"> }</span>
}
<span class="fc" id="L419"> getLogger().debug(&quot;Saving took &quot; + (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>
&quot;Intake IntakeServiceImpl.getGroup(groupName) is null&quot;);
}
<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>
&quot;Intake IntakeServiceImpl.getGroup(groupName): No XML definition for Group &quot;
+ groupName + &quot; found&quot;);
}
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(&quot;Could not get group &quot; + 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>
&quot;Intake IntakeServiceImpl.releaseGroup(groupName): &quot;
+ &quot;No XML definition for Group &quot; + groupName
+ &quot; found&quot;);
}
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(&quot;Could not get group &quot; + 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>
&quot;Intake IntakeServiceImpl.Size(groupName): No XML definition for Group &quot;
+ groupName + &quot; found&quot;);
}
<span class="nc" id="L518"> KeyedObjectPool&lt;String, Group&gt; 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&lt;String, Method&gt; 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(&quot;No setter Map for &quot; + className</span>
+ &quot; available!&quot;);
}
<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>
&quot;Intake: setter for '&quot; + propName + &quot;' in class '&quot;
+ className + &quot;' could not be found.&quot;);
}
<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&lt;String, Method&gt; 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&lt;String, Method&gt; 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(&quot;No getter Map for &quot; + className</span>
+ &quot; available!&quot;);
}
<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>
&quot;Intake: getter for '&quot; + propName + &quot;' in class '&quot;
+ className + &quot;' could not be found.&quot;);
}
<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&lt;String, Method&gt; 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&lt;String&gt;();</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 &lt; 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(&quot;none&quot;))</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(&quot;Path for serializing: &quot; + 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&lt;AppData, File&gt; appDataElements = null;</span>
<span class="fc" id="L729"> groupNames = new HashMap&lt;String, AppData&gt;();</span>
<span class="fc" id="L730"> groupKeyMap = new HashMap&lt;String, String&gt;();</span>
<span class="fc" id="L731"> groupNameMap = new HashMap&lt;String, String&gt;();</span>
<span class="fc" id="L732"> getterMap = new HashMap&lt;String, Map&lt;String,Method&gt;&gt;();</span>
<span class="fc" id="L733"> setterMap = new HashMap&lt;String, Map&lt;String,Method&gt;&gt;();</span>
<span class="fc" id="L734"> keyedPools = new HashMap&lt;AppData, KeyedObjectPool&lt;String, Group&gt;&gt;();</span>
<span class="fc" id="L736"> Set&lt;File&gt; xmlFiles = new HashSet&lt;File&gt;();</span>
<span class="fc" id="L738"> long timeStamp = 0;</span>
<span class="fc" id="L740"> getLogger().debug(&quot;logger is &quot; + 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(&quot;Path for XML File: &quot; + 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 = &quot;Could not read input file with path &quot;</span>
+ xmlPath + &quot;. Looking for file &quot; + 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(&quot;Added &quot; + xmlPath + &quot; as File to parse&quot;);</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() &gt; timeStamp ? xmlFile</span>
<span class="pc" id="L766"> .lastModified() : timeStamp;</span>
<span class="fc" id="L767"> }</span>
<span class="fc" id="L769"> Map&lt;AppData, File&gt; 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(&quot;Using the serialized map&quot;);</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(&quot;/intake.xsd&quot;);</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&lt;AppData, File&gt;();</span>
<span class="fc bfc" id="L797" title="All 2 branches covered."> for (File xmlFile : xmlFiles)</span>
{
<span class="fc" id="L799"> getLogger().debug(&quot;Now parsing: &quot; + 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(&quot;Saving AppData for &quot; + 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(&quot;Could not close file &quot; + xmlFile);</span>
<span class="fc" id="L820"> }</span>
}
}
<span class="fc" id="L823"> }</span>
<span class="fc" id="L825"> getLogger().debug(&quot;Parsing took &quot; + (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&lt;AppData, File&gt; 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&lt;Group&gt; 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&lt;Group&gt; 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>
&quot;Ignored redefinition of Group &quot; + groupName
<span class="nc" id="L854"> + &quot; or Key &quot; + g.getGID() + &quot; from &quot;</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>
&quot;Could not register fully qualified name &quot;
+ qualifiedName
+ &quot;, maybe two XML files have the same prefix. Ignoring it.&quot;);
}
}
// Init fields
<span class="fc bfc" id="L880" title="All 2 branches covered."> for (Field&lt;?&gt; 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&lt;String, Group&gt; factory =</span>
new Group.GroupFactory(appData);
<span class="fc" id="L891"> GenericKeyedObjectPoolConfig&lt;Group&gt; poolConfig = new GenericKeyedObjectPoolConfig&lt;Group&gt;();</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(&quot;fulcrum-intake-pool-&quot; + counter++);</span>
<span class="fc" id="L896"> keyedPools.put(appData,</span>
new GenericKeyedObjectPool&lt;String, Group&gt;(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(&quot;Intake Service is initialized now.&quot;);</span>
}
<span class="fc" id="L904"> }</span>
/**
* Note that the avalon.entry key=&quot;urn:avalon:home&quot;
* 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(&quot;urn:avalon:home&quot;).toString();</span>
<span class="fc" id="L919"> }</span>
/**
* Avalon component lifecycle method
*
* avalon.dependency type=&quot;org.apache.fulcrum.localization.LocalizationService&quot;
*
* @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>