/*
* Copyright 2001-2008 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
* $Id: Site.java 3918 2008-04-14 17:35:35Z gbevin $
*/
package com.uwyn.rife.engine;
import java.util.*;
import com.uwyn.rife.config.RifeConfig;
import com.uwyn.rife.continuations.ContinuationManager;
import com.uwyn.rife.engine.exceptions.DuplicateElementIdException;
import com.uwyn.rife.engine.exceptions.ElementIdNotFoundException;
import com.uwyn.rife.engine.exceptions.EngineException;
import com.uwyn.rife.engine.exceptions.FallbackUrlExistsException;
import com.uwyn.rife.engine.exceptions.UrlExistsException;
import com.uwyn.rife.rep.Participant;
import com.uwyn.rife.rep.Rep;
import com.uwyn.rife.resources.ResourceFinder;
import com.uwyn.rife.resources.exceptions.ResourceFinderErrorException;
import com.uwyn.rife.tools.TerracottaUtils;
import java.lang.reflect.Method;
import java.util.regex.Matcher;
/**
* A <code>Site</code> contains all the elements that will be used to handle
* web requests
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @version $Revision: 3918 $
* @since 1.0
*/
public class Site
{
public final static String DEFAULT_PARTICIPANT_NAME = "ParticipantSite";
private String mDeclarationName = null;
private SiteData mData = new SiteData();
private Set<SiteListener> mListeners = null;
private volatile Long mLastModificationCheck = 0L;
protected Site()
{
}
void setDeclarationName(String declarationName)
{
assert declarationName != null;
mDeclarationName = declarationName;
}
void setResourceFinder(ResourceFinder resourceFinder)
{
assert resourceFinder != null;
mData.mResourceFinder = resourceFinder;
}
void addResourceModificationTime(UrlResource location, long modificationTime)
{
if (RifeConfig.Engine.getSiteAutoReload())
{
if (null == mData.mResourceModificationTimes)
{
mData.mResourceModificationTimes = new HashMap<UrlResource, Long>();
}
mData.mResourceModificationTimes.put(location, new Long(modificationTime));
}
}
/**
* Retrieves a map of all the resources that were used to construct the site
* and their last modification time.
*
* @return the map of resources with their modification times; or
* <p><code>null</code> if the site was totally built manually or if the
* <code>SITE_AUTO_RELOAD</code> configuration parameter was not set to
* <code>true</code> at the time of construction.
* @since 1.0
*/
public Map<UrlResource, Long> getResourceModificationTimes()
{
if (null == mData.mResourceModificationTimes)
{
return Collections.EMPTY_MAP;
}
return mData.mResourceModificationTimes;
}
/**
* Resets the last modification check so that the next request will always
* check for modifications.
*
* @since 1.5.1
*/
public void resetLastModificationCheck()
{
synchronized (mLastModificationCheck)
{
mLastModificationCheck = 0L;
}
}
private boolean isModified()
throws EngineException
{
if (null != mData.mResourceModificationTimes)
{
long current_modification_time = 0;
for (Map.Entry<UrlResource, Long> resource_entry : mData.mResourceModificationTimes.entrySet())
{
try
{
current_modification_time = mData.mResourceFinder.getModificationTime(resource_entry.getKey().getUrl());
}
catch (ResourceFinderErrorException e)
{
// resource couldn't be found, consider it as not modified
return false;
}
if (resource_entry.getValue().longValue() != current_modification_time)
{
if (getClass().getClassLoader() instanceof EngineClassLoader &&
resource_entry.getKey().getUrl().getFile().endsWith(".class"))
{
((EngineClassLoader)getClass().getClassLoader())
.markClassAsModified(resource_entry.getKey().getSourceName());
}
return true;
}
}
}
return false;
}
private void checkModification()
throws EngineException
{
if (null != mData.mResourceModificationTimes)
{
synchronized (mLastModificationCheck)
{
if (System.currentTimeMillis() - mLastModificationCheck <= RifeConfig.Global.getAutoReloadDelay())
{
return;
}
mLastModificationCheck = System.currentTimeMillis();
}
synchronized (this)
{
if (isModified())
{
SiteBuilder builder = new SiteBuilder(mDeclarationName, mData.mResourceFinder);
Site new_site = null;
new_site = builder.getSite();
// only replace the site data when the root site builder was not manually processed
if (new_site != null &&
!SiteProcessorFactory.MANUAL_IDENTIFIER.equals(builder.getSiteProcessorIdentifier()))
{
populateFromOther(new_site);
}
fireModified();
}
}
}
}
/**
* Clears the cached data
*
* @since 1.5.1
*/
public synchronized void clearCaches()
{
this.mData.clearCaches();
}
/**
* Populates this site instance from another site instance.
* <p>This method is typically used during the implementation of a {@link SiteListener#modified}
* method. Doing this, will ensure that the active request as well as
* subsequent requests will be executed against the data of the other site
* instance.
*
* @param otherSite the other site that will be used to replace this site's
* data with
* @since 1.5
*/
public synchronized void populateFromOther(Site otherSite)
{
this.mData = otherSite.mData;
this.mData.clearCaches();
for (ElementInfo element_info : otherSite.getElementInfos())
{
element_info.setSite(this);
}
}
/**
* Indicates whether the default repository has a participant named
* "<code>ParticipantSite</code>".
*
* @return <code>true</code> if that participant was present; or
* <p><code>false</code> otherwise
* @see Rep#getDefaultRepository
* @see Participant
* @since 1.0
*/
public static boolean hasRepInstance()
{
return Rep.hasParticipant(DEFAULT_PARTICIPANT_NAME);
}
/**
* Retrieves the participant named "<code>ParticipantSite</code>" from the
* default repository.
*
* @return the participant; or
* <p><code>null</code> if no such participant was present
* @see Rep#getDefaultRepository
* @see Participant
* @since 1.0
*/
public static Participant getRepParticipant()
{
return Rep.getParticipant(DEFAULT_PARTICIPANT_NAME);
}
/**
* Retrieves the default object as a <code>Site</code> from the participant
* that was returned by {@link #getRepParticipant}.
*
* @return the site instance; or
* <p><code>null</code> if no "<code>ParticipantSite</code>" participant was
* present in the default repository
* @see #getRepParticipant
* @see Participant#getObject
* @since 1.0
*/
public static Site getRepInstance()
{
Participant participant = getRepParticipant();
if (null == participant)
{
return null;
}
return (Site)participant.getObject();
}
/**
* Retrieves the resource finder that was used to populate this site.
*
* @return this site's resource finder
* @since 1.4
*/
public ResourceFinder getResourceFinder()
{
return mData.mResourceFinder;
}
/**
* Retrieves the continuation manager that is used by this site.
*
* @return the site's contiuation manager
* @since 1.5
*/
public ContinuationManager getContinuationManager()
{
return mData.mContinuationManager;
}
/**
* Retrieves the collection of all the element IDs that are present in
* this site.
*
* @return the collection of all the element IDs in this site
* @since 1.0
*/
public Collection<String> getIds()
{
return mData.mIdMapping.keySet();
}
Collection<ElementInfo> getElementInfos()
{
return mData.mIdMapping.values();
}
void addElementInfo(String id, ElementInfo elementInfo, String url)
throws EngineException
{
assert id != null;
assert id.length() > 0;
assert elementInfo != null;
if (mData.mIdMapping.containsKey(id))
{
throw new DuplicateElementIdException(id);
}
elementInfo.setId(id);
mData.mIdMapping.put(id, elementInfo);
elementInfo.setSite(this);
if (url != null)
{
// ensure that the root url always is '/' and not ''
if (0 == url.length())
{
url = "/";
}
elementInfo.setUrl(url);
mapElementId(id, url);
}
}
void mapElementId(String id, String url)
throws EngineException
{
assert id != null;
assert id.length() > 0;
assert url != null;
ElementInfo element_info = mData.mIdMapping.get(id);
if (null == element_info)
{
throw new ElementIdNotFoundException(id);
}
// ensure that the root url always is '/' and not ''
if (0 == url.length())
{
url = "/";
}
mData.mUrls = null;
if (element_info.isPathInfoUsed())
{
List<ElementInfo> elements = mData.mPathinfoUrlMapping.get(url);
if (null == elements)
{
elements = new ArrayList<ElementInfo>();
mData.mPathinfoUrlMapping.put(url, elements);
}
elements.add(element_info);
}
else
{
if (mData.mUrlMapping.containsKey(url))
{
throw new UrlExistsException(id, url, mData.mUrlMapping.get(url).getId());
}
mData.mUrlMapping.put(url, element_info);
}
}
void addFallback(ElementInfo elementInfo, String url)
throws EngineException
{
assert elementInfo != null;
if (url != null)
{
if (mData.mFallbackUrlMapping.containsKey(url))
{
throw new FallbackUrlExistsException(url);
}
mData.mFallbackUrlMapping.put(url, elementInfo);
}
}
/**
* Searches which element would be used as a fallback for a particilar URL.
*
* @param url the URL for which a fallback should be found
* @return the fallback element; or
* <p><code>null</code> if no fallback is available for that URL
* @since 1.0
*/
public ElementInfo searchFallback(String url)
throws EngineException
{
if (null == url) throw new IllegalArgumentException("url can't be null;");
checkModification();
String best_match = null;
if (0 == url.length())
{
url = "/";
}
for (String fallback_url : mData.mFallbackUrlMapping.keySet())
{
if (url.startsWith(fallback_url) &&
(null == best_match || fallback_url.length() > best_match.length()))
{
best_match = fallback_url;
}
}
if (best_match != null)
{
return mData.mFallbackUrlMapping.get(best_match);
}
else
{
return null;
}
}
/**
* Indicates whether a certain URL has a mapping in this site.
*
* @param url the URL that should be looked up
* @return <code>true</code> if the URL corresponds to and element; or
* <p><code>false</code> otherwise
* @since 1.0
*/
public boolean containsUrl(String url)
{
if (null == url) throw new IllegalArgumentException("url can't be null;");
checkModification();
if (0 == url.length())
{
url = "/";
}
if (mData.mUrlMapping.containsKey(url))
{
return true;
}
if (url.length() > 0 &&
'/' == url.charAt(url.length()-1))
{
String stripped_url = url.substring(0, url.length()-1);
// if the url contains a dot in the last part, it shouldn't be
// seen as simulating a directory
if (stripped_url.lastIndexOf('.') <= stripped_url.lastIndexOf('/') &&
mData.mUrlMapping.containsKey(stripped_url))
{
return true;
}
}
if (mData.mPathinfoUrlMapping.containsKey(url))
{
return true;
}
return false;
}
/**
* Looks up the information of the element that is responsible for handling
* a certain URL and pathinfo.
*
* @param url the URL that should be looked up
* @param pathinfo the pathinfo that should be taken into account
* @return the corresponding element information; or
* <p><code>null</code> if the URL and pathinfo aren't registered in this site
* @since 1.4
*/
public ElementInfo resolveUrl(String url, String pathinfo)
throws EngineException
{
if (null == url) throw new IllegalArgumentException("url can't be null;");
checkModification();
if (0 == url.length())
{
url = "/";
}
ElementInfo result;
if (null == pathinfo)
{
result = mData.mUrlMapping.get(url);
if (result != null)
{
return result;
}
if (url.length() > 0 &&
'/' == url.charAt(url.length()-1))
{
String stripped_url = url.substring(0, url.length()-1);
// if the url contains a dot in the last part, it shouldn't be
// seen as simulating a directory
if (stripped_url.lastIndexOf('.') <= stripped_url.lastIndexOf('/'))
{
result = mData.mUrlMapping.get(stripped_url);
if (result != null)
{
return result;
}
}
}
}
result = resolvePathInfoUrl(url, pathinfo);
return result;
}
/**
* Looks for an element that corresponds to a particular request URL.
* <p>
* This method will determine the best element match by stepping up the path
* segments. It will also look for fallback elements, cater for trailing
* slashes, and figure out the correct pathinfo.
* <p>
* Basically, this is the method that is used by the <code>Gate</code> to
* figure out which element to service when a request arrives.
*
* @param elementUrl the URL that will be used to search for the element
*
* @return an instance of <code>ElementToService</code> when an element match
* was found; or
* <p><code>null</code> if no suitable element could be found.
*
* @since 1.6
*/
public ElementToService findElementForRequest(String elementUrl)
{
// obtain the element info that mapped to the requested path info
ElementInfo element_info = null;
StringBuilder element_url_buffer = new StringBuilder(elementUrl);
int element_url_location = -1;
String element_path_info = "";
String pathinfo = null;
do
{
// if a slash was found in the url, it was stripped away
// and thus the only urls that should match then are path info
// urls
if (element_url_location > -1)
{
pathinfo = elementUrl.substring(element_url_location);
}
element_info = resolveUrl(element_url_buffer.toString(), pathinfo);
if (element_info != null)
{
break;
}
element_url_location = element_url_buffer.lastIndexOf("/");
if (-1 == element_url_location)
{
break;
}
element_url_buffer.setLength(element_url_location);
}
while (element_url_location != -1);
// no target element, get the fallback element
if (null == element_info)
{
element_info = searchFallback(elementUrl);
if (null == element_info)
{
return null;
}
}
// otherwise get the target element's path info
else
{
// only accept pathinfo if the element accepts it
if (!element_info.isPathInfoUsed() &&
elementUrl.length() != element_url_buffer.length())
{
// check for a fallback element
element_info = searchFallback(elementUrl);
if (null == element_info)
{
return null;
}
}
else if (element_info.isPathInfoUsed())
{
// construct the element path info
element_path_info = elementUrl.substring(element_url_buffer.length());
// always ensure that the path info starts with a slash
// this can not be present if the concerned element is
// an arrival for instance
if (!element_path_info.startsWith("/"))
{
element_path_info = "/"+element_path_info;
}
}
}
// if no element info was found, don't return an ElementToService match
if (null == element_info)
{
return null;
}
return new ElementToService(element_info, element_path_info);
}
private ElementInfo resolvePathInfoUrl(String url, String pathinfo)
throws EngineException
{
List<ElementInfo> elements = mData.mPathinfoUrlMapping.get(url);
if (null == elements ||
0 == elements.size())
{
return null;
}
// if a pathinfo was provided, check the pathinfo mappings
// for the first that matches
if (pathinfo != null)
{
for (ElementInfo element : elements)
{
if (element.hasPathInfoMappings())
{
for (PathInfoMapping mapping : element.getPathInfoMappings())
{
Matcher matcher = mapping.getRegexp().matcher(pathinfo);
if (matcher.matches())
{
return element;
}
}
}
}
}
// return the first element that handles the url and doesn't have
// any pathinfo mappings
for (ElementInfo element : elements)
{
if (!element.hasPathInfoMappings() ||
PathInfoMode.LOOSE.equals(element.getPathInfoMode()))
{
return element;
}
}
return null;
}
/**
* Retrieves the collection of all the URLs that are present in this site.
*
* @return the collection of all the URLs in this site
* @since 1.0
*/
public Collection<String> getUrls()
{
if (null == mData.mUrls)
{
ArrayList urls = new ArrayList<String>(mData.mUrlMapping.keySet());
urls.addAll(mData.mPathinfoUrlMapping.keySet());
mData.mUrls = urls;
}
return mData.mUrls;
}
/**
* Indicates whether an absolute element ID is present in the site.
*
* @param id the absolute element ID that should be looked up
* @return <code>true</code> if the element ID could be found; or
* <p><code>false</code> otherwise
* @since 1.0
*/
public boolean containsId(String id)
{
if (null == id) throw new IllegalArgumentException("id can't be null.");
if (0 == id.length()) throw new IllegalArgumentException("id can't be empty.");
return mData.mIdMapping.containsKey(id);
}
/**
* Retrieves the element information in this site that corresponds to
* provided absolute element ID.
*
* @param id the absolute element ID that should be looked up
* @return the corresponding element information; or
* <p><code>null</code> if the absolute element ID couldn't be found
* @since 1.0
*/
public ElementInfo resolveId(String id)
throws EngineException
{
return resolveId(id, null);
}
/**
* Retrieves the element information in this site that corresponds to
* provided element ID.
*
* @param id the element ID that should be looked up
* @param reference the element information that should be used as a
* reference to look up the element information from when a relative ID
* is provided
* @return the corresponding element information; or
* <p><code>null</code> if the element ID couldn't be found
* @since 1.0
*/
public ElementInfo resolveId(String id, ElementInfo reference)
throws EngineException
{
if (null == id) throw new IllegalArgumentException("id can't be null.");
if (0 == id.length()) throw new IllegalArgumentException("id can't be empty.");
checkModification();
String absolute_id = getCanonicalId(getAbsoluteId(id, reference));
return mData.mIdMapping.get(absolute_id);
}
/**
* Transforms the provided element ID into an absolute element ID.
*
* @param id the element ID that should be transformed
* @param reference the element information that should be used as a
* reference to look up the element information from when a relative ID
* is provided
* @return the absolute element ID that corresponds to the provided
* element ID
* @since 1.0
*/
public static String getAbsoluteId(String id, ElementInfo reference)
{
if (null == id) throw new IllegalArgumentException("id can't be null.");
if (0 == id.length()) throw new IllegalArgumentException("id can't be empty.");
// resolve a relative element id
if (!id.startsWith("."))
{
if (null == reference) throw new IllegalArgumentException("reference can't be null for a relative element id.");
String path_id = reference.getReferenceId().substring(0, reference.getReferenceId().lastIndexOf(".")+1);
StringBuilder absolute_id = new StringBuilder(path_id);
absolute_id.append(id);
id = absolute_id.toString();
}
return id;
}
/**
* Transforms the provided element ID into a canonical ID without any
* parent indicators.
*
* @param id the element ID that should be transformed
* @return the canonical element ID that corresponds to the provided
* element ID
* @since 1.0
*/
public static String getCanonicalId(String id)
{
if (null == id)
{
return null;
}
StringBuilder canonical_id = new StringBuilder();
StringTokenizer id_tok = new StringTokenizer(id, ".^", true);
String token = null;
int seperator_index = -1;
while (id_tok.hasMoreTokens())
{
token = id_tok.nextToken();
if (token.equals("."))
{
// do nothing
}
else if (token.equals("^"))
{
// fold back to the previous element path part
// and don't go further than an empty string
seperator_index = canonical_id.lastIndexOf(".");
if (seperator_index != -1)
{
canonical_id.setLength(seperator_index);
}
}
else
{
canonical_id.append(".");
canonical_id.append(token);
}
}
// handle arrival elements
if (id.endsWith("."))
{
canonical_id.append(".");
}
return canonical_id.toString();
}
/**
* Adds the specified listener to receive site-related events.
* If <code>listener</code> is null, no exception is thrown and no action
* is performed.
*
* @param listener The site listener that will be added.
* @see SiteListener
* @see #removeListener(SiteListener)
* @since 1.5
*/
public void addListener(SiteListener listener)
{
if (null == listener) return;
if (null == mListeners)
{
mListeners = new HashSet<SiteListener>();
}
mListeners.add(listener);
}
/**
* Removes the site listener so that it no longer receives any events. This
* method performs no function, nor does it throw an exception if the listener
* specified by the argument was not previously added to this component or is
* <code>null</code>.
*
* @param listener The site listener that will be removed.
* @see SiteListener
* @see #addListener(SiteListener)
* @since 1.5
*/
public void removeListener(SiteListener listener)
{
if (mListeners != null)
{
mListeners.remove(listener);
}
}
/**
* Notifies the registered listeners that one of the site's resources has
* been detected as being modified.
*
* @see SiteListener
* @since 1.5
*/
public void fireModified()
{
if (mListeners != null &&
mListeners.size() > 0)
{
for (SiteListener listener : mListeners)
{
listener.modified(this);
}
}
}
Map<String, Method> getCachedOutputGetters(String elementId)
{
return mData.mOutputGettersCache.get(elementId);
}
void putCachedOutputGetters(String elementId, Map<String, Method> outputGetters)
{
synchronized (mData)
{
mData.mOutputGettersCache.put(elementId, outputGetters);
}
}
Map<String, Method> getCachedOutbeanGetters(String elementId)
{
return mData.mOutbeanGettersCache.get(elementId);
}
void putCachedOutbeanGetters(String elementId, Map<String, Method> outbeanGetters)
{
synchronized (mData)
{
mData.mOutbeanGettersCache.put(elementId, outbeanGetters);
}
}
Map<String, Method> getCachedOutcookieGetters(String elementId)
{
return mData.mOutcookieGettersCache.get(elementId);
}
void putCachedOutcookieGetters(String elementId, Map<String, Method> outcookieGetters)
{
synchronized (mData)
{
mData.mOutcookieGettersCache.put(elementId, outcookieGetters);
}
}
Map<String, Method> getCachedPropertySetters(String elementId)
{
return mData.mPropertySettersCache.get(elementId);
}
void putCachedPropertySetters(String elementId, Map<String, Method> propertySetters)
{
synchronized (mData)
{
mData.mPropertySettersCache.put(elementId, propertySetters);
}
}
Map<String, Method> getCachedIncookieSetters(String elementId)
{
return mData.mIncookieSettersCache.get(elementId);
}
void putCachedIncookieSetters(String elementId, Map<String, Method> incookieSetters)
{
synchronized (mData)
{
mData.mIncookieSettersCache.put(elementId, incookieSetters);
}
}
Map<String, Method> getCachedInputSetters(String elementId)
{
return mData.mInputSettersCache.get(elementId);
}
void putCachedInputSetters(String elementId, Map<String, Method> inputSetters)
{
synchronized (mData)
{
mData.mInputSettersCache.put(elementId, inputSetters);
}
}
Map<String, Method> getCachedInbeanSetters(String elementId)
{
return mData.mInbeanSettersCache.get(elementId);
}
void putCachedInbeanSetters(String elementId, Map<String, Method> inbeanSetters)
{
synchronized (mData)
{
mData.mInbeanSettersCache.put(elementId, inbeanSetters);
}
}
SubmissionSettersCache getSubmissionSettersCache(String elementId)
{
return mData.mSubmissionSettersCache.get(elementId);
}
void putSubmissionSettersCache(String elementId, SubmissionSettersCache submissionSettersCache)
{
synchronized (mData)
{
mData.mSubmissionSettersCache.put(elementId, submissionSettersCache);
}
}
private class SiteData
{
private final Map<String, ElementInfo> mUrlMapping = new LinkedHashMap<String, ElementInfo>();
private final Map<String, List<ElementInfo>> mPathinfoUrlMapping = new LinkedHashMap<String, List<ElementInfo>>();
private final Map<String, ElementInfo> mFallbackUrlMapping = new HashMap<String, ElementInfo>();
private final Map<String, ElementInfo> mIdMapping = new LinkedHashMap<String, ElementInfo>();
private final ContinuationManager<ElementSupport> mContinuationManager = new ContinuationManager<ElementSupport>(EngineContinuationConfigRuntimeSingleton.INSTANCE);
private List<String> mUrls = null;
private ResourceFinder mResourceFinder = null;
private HashMap<UrlResource, Long> mResourceModificationTimes = null;
private Map<String, Map<String, Method>> mOutputGettersCache;
private Map<String, Map<String, Method>> mOutbeanGettersCache;
private Map<String, Map<String, Method>> mOutcookieGettersCache;
private Map<String, Map<String, Method>> mPropertySettersCache;
private Map<String, Map<String, Method>> mIncookieSettersCache;
private Map<String, Map<String, Method>> mInputSettersCache;
private Map<String, Map<String, Method>> mInbeanSettersCache;
private Map<String, SubmissionSettersCache> mSubmissionSettersCache;
SiteData()
{
clearCaches();
}
void clearCaches()
{
if (TerracottaUtils.isTcPresent())
{
mOutputGettersCache = new HashMap<String, Map<String, Method>>();
mOutbeanGettersCache = new HashMap<String, Map<String, Method>>();
mOutcookieGettersCache = new HashMap<String, Map<String, Method>>();
mPropertySettersCache = new HashMap<String, Map<String, Method>>();
mIncookieSettersCache = new HashMap<String, Map<String, Method>>();
mInputSettersCache = new HashMap<String, Map<String, Method>>();
mInbeanSettersCache = new HashMap<String, Map<String, Method>>();
mSubmissionSettersCache = new HashMap<String, SubmissionSettersCache>();
}
else
{
mOutputGettersCache = new WeakHashMap<String, Map<String, Method>>();
mOutbeanGettersCache = new WeakHashMap<String, Map<String, Method>>();
mOutcookieGettersCache = new WeakHashMap<String, Map<String, Method>>();
mPropertySettersCache = new WeakHashMap<String, Map<String, Method>>();
mIncookieSettersCache = new WeakHashMap<String, Map<String, Method>>();
mInputSettersCache = new WeakHashMap<String, Map<String, Method>>();
mInbeanSettersCache = new WeakHashMap<String, Map<String, Method>>();
mSubmissionSettersCache = new WeakHashMap<String, SubmissionSettersCache>();
}
}
}
}
class SubmissionSettersCache
{
private Map<String, Map<String, Method>> mSubmissionparamSettersCache = new HashMap<String, Map<String, Method>>();
private Map<String, Map<String, Method>> mSubmissionbeanSettersCache = new HashMap<String, Map<String, Method>>();
private Map<String, Map<String, Method>> mUploadedfileSettersCache = new HashMap<String, Map<String, Method>>();
Map<String, Method> getCachedSubmissionparamSetters(String submissionName)
{
return mSubmissionparamSettersCache.get(submissionName);
}
synchronized void putCachedSubmissionparamSetters(String submissionName, Map<String, Method> submissionparamSetters)
{
mSubmissionparamSettersCache.put(submissionName, submissionparamSetters);
}
Map<String, Method> getCachedSubmissionbeanSetters(String submissionName)
{
return mSubmissionbeanSettersCache.get(submissionName);
}
synchronized void putCachedSubmissionbeanSetters(String submissionName, Map<String, Method> submissionbeanSetters)
{
mSubmissionbeanSettersCache.put(submissionName, submissionbeanSetters);
}
Map<String, Method> getCachedUploadedfileSetters(String submissionName)
{
return mUploadedfileSettersCache.get(submissionName);
}
synchronized void putCachedUploadedfileSetters(String submissionName, Map<String, Method> uploadedfileSetters)
{
mUploadedfileSettersCache.put(submissionName, uploadedfileSetters);
}
}