001: /*
002: * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: * $Id: Site.java 3806 2007-06-24 21:12:50Z gbevin $
007: */
008: package com.uwyn.rife.engine;
009:
010: import java.util.*;
011:
012: import com.uwyn.rife.config.RifeConfig;
013: import com.uwyn.rife.continuations.ContinuationManager;
014: import com.uwyn.rife.engine.exceptions.DuplicateElementIdException;
015: import com.uwyn.rife.engine.exceptions.ElementIdNotFoundException;
016: import com.uwyn.rife.engine.exceptions.EngineException;
017: import com.uwyn.rife.engine.exceptions.FallbackUrlExistsException;
018: import com.uwyn.rife.engine.exceptions.UrlExistsException;
019: import com.uwyn.rife.rep.Participant;
020: import com.uwyn.rife.rep.Rep;
021: import com.uwyn.rife.resources.ResourceFinder;
022: import com.uwyn.rife.resources.exceptions.ResourceFinderErrorException;
023: import com.uwyn.rife.tools.TerracottaUtils;
024: import java.lang.reflect.Method;
025: import java.util.regex.Matcher;
026:
027: /**
028: * A <code>Site</code> contains all the elements that will be used to handle
029: * web requests
030: *
031: * @author Geert Bevin (gbevin[remove] at uwyn dot com)
032: * @version $Revision: 3806 $
033: * @since 1.0
034: */
035: public class Site {
036: public final static String DEFAULT_PARTICIPANT_NAME = "ParticipantSite";
037:
038: private String mDeclarationName = null;
039: private SiteData mData = new SiteData();
040: private Set<SiteListener> mListeners = null;
041: private volatile Long mLastModificationCheck = 0L;
042:
043: protected Site() {
044: }
045:
046: void setDeclarationName(String declarationName) {
047: assert declarationName != null;
048:
049: mDeclarationName = declarationName;
050: }
051:
052: void setResourceFinder(ResourceFinder resourceFinder) {
053: assert resourceFinder != null;
054:
055: mData.mResourceFinder = resourceFinder;
056: }
057:
058: void addResourceModificationTime(UrlResource location,
059: long modificationTime) {
060: if (RifeConfig.Engine.getSiteAutoReload()) {
061: if (null == mData.mResourceModificationTimes) {
062: mData.mResourceModificationTimes = new HashMap<UrlResource, Long>();
063: }
064:
065: mData.mResourceModificationTimes.put(location, new Long(
066: modificationTime));
067: }
068: }
069:
070: /**
071: * Retrieves a map of all the resources that were used to construct the site
072: * and their last modification time.
073: *
074: * @return the map of resources with their modification times; or
075: * <p><code>null</code> if the site was totally built manually or if the
076: * <code>SITE_AUTO_RELOAD</code> configuration parameter was not set to
077: * <code>true</code> at the time of construction.
078: * @since 1.0
079: */
080: public Map<UrlResource, Long> getResourceModificationTimes() {
081: if (null == mData.mResourceModificationTimes) {
082: return Collections.EMPTY_MAP;
083: }
084: return mData.mResourceModificationTimes;
085: }
086:
087: /**
088: * Resets the last modification check so that the next request will always
089: * check for modifications.
090: *
091: * @since 1.5.1
092: */
093: public void resetLastModificationCheck() {
094: synchronized (mLastModificationCheck) {
095: mLastModificationCheck = 0L;
096: }
097: }
098:
099: private boolean isModified() throws EngineException {
100: if (null != mData.mResourceModificationTimes) {
101: long current_modification_time = 0;
102:
103: for (Map.Entry<UrlResource, Long> resource_entry : mData.mResourceModificationTimes
104: .entrySet()) {
105: try {
106: current_modification_time = mData.mResourceFinder
107: .getModificationTime(resource_entry
108: .getKey().getUrl());
109: } catch (ResourceFinderErrorException e) {
110: // resource couldn't be found, consider it as not modified
111: return false;
112: }
113:
114: if (resource_entry.getValue().longValue() != current_modification_time) {
115: if (getClass().getClassLoader() instanceof EngineClassLoader
116: && resource_entry.getKey().getUrl()
117: .getFile().endsWith(".class")) {
118: ((EngineClassLoader) getClass()
119: .getClassLoader())
120: .markClassAsModified(resource_entry
121: .getKey().getSourceName());
122: }
123: return true;
124: }
125: }
126: }
127:
128: return false;
129: }
130:
131: private void checkModification() throws EngineException {
132: if (null != mData.mResourceModificationTimes) {
133: synchronized (mLastModificationCheck) {
134: if (System.currentTimeMillis() - mLastModificationCheck <= RifeConfig.Global
135: .getAutoReloadDelay()) {
136: return;
137: }
138: mLastModificationCheck = System.currentTimeMillis();
139: }
140:
141: synchronized (this ) {
142: if (isModified()) {
143: SiteBuilder builder = new SiteBuilder(
144: mDeclarationName, mData.mResourceFinder);
145: Site new_site = null;
146:
147: new_site = builder.getSite();
148:
149: // only replace the site data when the root site builder was not manually processed
150: if (new_site != null
151: && !SiteProcessorFactory.MANUAL_IDENTIFIER
152: .equals(builder
153: .getSiteProcessorIdentifier())) {
154: populateFromOther(new_site);
155: }
156:
157: fireModified();
158: }
159: }
160: }
161: }
162:
163: /**
164: * Clears the cached data
165: *
166: * @since 1.5.1
167: */
168: public synchronized void clearCaches() {
169: this .mData.clearCaches();
170: }
171:
172: /**
173: * Populates this site instance from another site instance.
174: * <p>This method is typically used during the implementation of a {@link SiteListener#modified}
175: * method. Doing this, will ensure that the active request as well as
176: * subsequent requests will be executed against the data of the other site
177: * instance.
178: *
179: * @param otherSite the other site that will be used to replace this site's
180: * data with
181: * @since 1.5
182: */
183: public synchronized void populateFromOther(Site otherSite) {
184: this .mData = otherSite.mData;
185: this .mData.clearCaches();
186:
187: for (ElementInfo element_info : otherSite.getElementInfos()) {
188: element_info.setSite(this );
189: }
190: }
191:
192: /**
193: * Indicates whether the default repository has a participant named
194: * "<code>ParticipantSite</code>".
195: *
196: * @return <code>true</code> if that participant was present; or
197: * <p><code>false</code> otherwise
198: * @see Rep#getDefaultRepository
199: * @see Participant
200: * @since 1.0
201: */
202: public static boolean hasRepInstance() {
203: return Rep.hasParticipant(DEFAULT_PARTICIPANT_NAME);
204: }
205:
206: /**
207: * Retrieves the participant named "<code>ParticipantSite</code>" from the
208: * default repository.
209: *
210: * @return the participant; or
211: * <p><code>null</code> if no such participant was present
212: * @see Rep#getDefaultRepository
213: * @see Participant
214: * @since 1.0
215: */
216: public static Participant getRepParticipant() {
217: return Rep.getParticipant(DEFAULT_PARTICIPANT_NAME);
218: }
219:
220: /**
221: * Retrieves the default object as a <code>Site</code> from the participant
222: * that was returned by {@link #getRepParticipant}.
223: *
224: * @return the site instance; or
225: * <p><code>null</code> if no "<code>ParticipantSite</code>" participant was
226: * present in the default repository
227: * @see #getRepParticipant
228: * @see Participant#getObject
229: * @since 1.0
230: */
231: public static Site getRepInstance() {
232: Participant participant = getRepParticipant();
233: if (null == participant) {
234: return null;
235: }
236:
237: return (Site) participant.getObject();
238: }
239:
240: /**
241: * Retrieves the resource finder that was used to populate this site.
242: *
243: * @return this site's resource finder
244: * @since 1.4
245: */
246: public ResourceFinder getResourceFinder() {
247: return mData.mResourceFinder;
248: }
249:
250: /**
251: * Retrieves the continuation manager that is used by this site.
252: *
253: * @return the site's contiuation manager
254: * @since 1.5
255: */
256: public ContinuationManager getContinuationManager() {
257: return mData.mContinuationManager;
258: }
259:
260: /**
261: * Retrieves the collection of all the element IDs that are present in
262: * this site.
263: *
264: * @return the collection of all the element IDs in this site
265: * @since 1.0
266: */
267: public Collection<String> getIds() {
268: return mData.mIdMapping.keySet();
269: }
270:
271: Collection<ElementInfo> getElementInfos() {
272: return mData.mIdMapping.values();
273: }
274:
275: void addElementInfo(String id, ElementInfo elementInfo, String url)
276: throws EngineException {
277: assert id != null;
278: assert id.length() > 0;
279: assert elementInfo != null;
280:
281: if (mData.mIdMapping.containsKey(id)) {
282: throw new DuplicateElementIdException(id);
283: }
284: elementInfo.setId(id);
285: mData.mIdMapping.put(id, elementInfo);
286:
287: elementInfo.setSite(this );
288:
289: if (url != null) {
290: // ensure that the root url always is '/' and not ''
291: if (0 == url.length()) {
292: url = "/";
293: }
294:
295: elementInfo.setUrl(url);
296:
297: mapElementId(id, url);
298: }
299: }
300:
301: void mapElementId(String id, String url) throws EngineException {
302: assert id != null;
303: assert id.length() > 0;
304: assert url != null;
305:
306: ElementInfo element_info = mData.mIdMapping.get(id);
307: if (null == element_info) {
308: throw new ElementIdNotFoundException(id);
309: }
310:
311: // ensure that the root url always is '/' and not ''
312: if (0 == url.length()) {
313: url = "/";
314: }
315:
316: mData.mUrls = null;
317: if (element_info.isPathInfoUsed()) {
318: List<ElementInfo> elements = mData.mPathinfoUrlMapping
319: .get(url);
320: if (null == elements) {
321: elements = new ArrayList<ElementInfo>();
322: mData.mPathinfoUrlMapping.put(url, elements);
323: }
324:
325: elements.add(element_info);
326: } else {
327: if (mData.mUrlMapping.containsKey(url)) {
328: throw new UrlExistsException(id, url, mData.mUrlMapping
329: .get(url).getId());
330: }
331:
332: mData.mUrlMapping.put(url, element_info);
333: }
334: }
335:
336: void addFallback(ElementInfo elementInfo, String url)
337: throws EngineException {
338: assert elementInfo != null;
339:
340: if (url != null) {
341: if (mData.mFallbackUrlMapping.containsKey(url)) {
342: throw new FallbackUrlExistsException(url);
343: }
344: mData.mFallbackUrlMapping.put(url, elementInfo);
345: }
346: }
347:
348: /**
349: * Searches which element would be used as a fallback for a particilar URL.
350: *
351: * @param url the URL for which a fallback should be found
352: * @return the fallback element; or
353: * <p><code>null</code> if no fallback is available for that URL
354: * @since 1.0
355: */
356: public ElementInfo searchFallback(String url)
357: throws EngineException {
358: if (null == url)
359: throw new IllegalArgumentException("url can't be null;");
360:
361: checkModification();
362:
363: String best_match = null;
364: if (0 == url.length()) {
365: url = "/";
366: }
367:
368: for (String fallback_url : mData.mFallbackUrlMapping.keySet()) {
369: if (url.startsWith(fallback_url)
370: && (null == best_match || fallback_url.length() > best_match
371: .length())) {
372: best_match = fallback_url;
373: }
374: }
375:
376: if (best_match != null) {
377: return mData.mFallbackUrlMapping.get(best_match);
378: } else {
379: return null;
380: }
381: }
382:
383: /**
384: * Indicates whether a certain URL has a mapping in this site.
385: *
386: * @param url the URL that should be looked up
387: * @return <code>true</code> if the URL corresponds to and element; or
388: * <p><code>false</code> otherwise
389: * @since 1.0
390: */
391: public boolean containsUrl(String url) {
392: if (null == url)
393: throw new IllegalArgumentException("url can't be null;");
394:
395: checkModification();
396:
397: if (0 == url.length()) {
398: url = "/";
399: }
400:
401: if (mData.mUrlMapping.containsKey(url)) {
402: return true;
403: }
404:
405: if (url.length() > 0 && '/' == url.charAt(url.length() - 1)) {
406: String stripped_url = url.substring(0, url.length() - 1);
407: // if the url contains a dot in the last part, it shouldn't be
408: // seen as simulating a directory
409: if (stripped_url.lastIndexOf('.') <= stripped_url
410: .lastIndexOf('/')
411: && mData.mUrlMapping.containsKey(stripped_url)) {
412: return true;
413: }
414: }
415:
416: if (mData.mPathinfoUrlMapping.containsKey(url)) {
417: return true;
418: }
419:
420: return false;
421: }
422:
423: /**
424: * Looks up the information of the element that is responsible for handling
425: * a certain URL and pathinfo.
426: *
427: * @param url the URL that should be looked up
428: * @param pathinfo the pathinfo that should be taken into account
429: * @return the corresponding element information; or
430: * <p><code>null</code> if the URL and pathinfo aren't registered in this site
431: * @since 1.4
432: */
433: public ElementInfo resolveUrl(String url, String pathinfo)
434: throws EngineException {
435: if (null == url)
436: throw new IllegalArgumentException("url can't be null;");
437:
438: checkModification();
439:
440: if (0 == url.length()) {
441: url = "/";
442: }
443:
444: ElementInfo result;
445:
446: if (null == pathinfo) {
447: result = mData.mUrlMapping.get(url);
448: if (result != null) {
449: return result;
450: }
451:
452: if (url.length() > 0 && '/' == url.charAt(url.length() - 1)) {
453: String stripped_url = url
454: .substring(0, url.length() - 1);
455: // if the url contains a dot in the last part, it shouldn't be
456: // seen as simulating a directory
457: if (stripped_url.lastIndexOf('.') <= stripped_url
458: .lastIndexOf('/')) {
459: result = mData.mUrlMapping.get(stripped_url);
460: if (result != null) {
461: return result;
462: }
463: }
464: }
465: }
466:
467: result = resolvePathInfoUrl(url, pathinfo);
468:
469: return result;
470: }
471:
472: /**
473: * Looks for an element that corresponds to a particular request URL.
474: * <p>
475: * This method will determine the best element match by stepping up the path
476: * segments. It will also look for fallback elements, cater for trailing
477: * slashes, and figure out the correct pathinfo.
478: * <p>
479: * Basically, this is the method that is used by the <code>Gate</code> to
480: * figure out which element to service when a request arrives.
481: *
482: * @param elementUrl the URL that will be used to search for the element
483: *
484: * @return an instance of <code>ElementToService</code> when an element match
485: * was found; or
486: * <p><code>null</code> if no suitable element could be found.
487: *
488: * @since 1.6
489: */
490: public ElementToService findElementForRequest(String elementUrl) {
491: // obtain the element info that mapped to the requested path info
492: ElementInfo element_info = null;
493: StringBuilder element_url_buffer = new StringBuilder(elementUrl);
494: int element_url_location = -1;
495: String element_path_info = "";
496: String pathinfo = null;
497: do {
498: // if a slash was found in the url, it was stripped away
499: // and thus the only urls that should match then are path info
500: // urls
501: if (element_url_location > -1) {
502: pathinfo = elementUrl.substring(element_url_location);
503: }
504: element_info = resolveUrl(element_url_buffer.toString(),
505: pathinfo);
506:
507: if (element_info != null) {
508: break;
509: }
510:
511: element_url_location = element_url_buffer.lastIndexOf("/");
512: if (-1 == element_url_location) {
513: break;
514: }
515: element_url_buffer.setLength(element_url_location);
516: } while (element_url_location != -1);
517:
518: // no target element, get the fallback element
519: if (null == element_info) {
520: element_info = searchFallback(elementUrl);
521: if (null == element_info) {
522: return null;
523: }
524: }
525: // otherwise get the target element's path info
526: else {
527: // only accept pathinfo if the element accepts it
528: if (!element_info.isPathInfoUsed()
529: && elementUrl.length() != element_url_buffer
530: .length()) {
531: // check for a fallback element
532: element_info = searchFallback(elementUrl);
533: if (null == element_info) {
534: return null;
535: }
536: } else if (element_info.isPathInfoUsed()) {
537: // construct the element path info
538: element_path_info = elementUrl
539: .substring(element_url_buffer.length());
540: // always ensure that the path info starts with a slash
541: // this can not be present if the concerned element is
542: // an arrival for instance
543: if (!element_path_info.startsWith("/")) {
544: element_path_info = "/" + element_path_info;
545: }
546: }
547: }
548:
549: // if no element info was found, don't return an ElementToService match
550: if (null == element_info) {
551: return null;
552: }
553:
554: return new ElementToService(element_info, element_path_info);
555: }
556:
557: private ElementInfo resolvePathInfoUrl(String url, String pathinfo)
558: throws EngineException {
559: List<ElementInfo> elements = mData.mPathinfoUrlMapping.get(url);
560: if (null == elements || 0 == elements.size()) {
561: return null;
562: }
563:
564: // if a pathinfo was provided, check the pathinfo mappings
565: // for the first that matches
566: if (pathinfo != null) {
567: for (ElementInfo element : elements) {
568: if (element.hasPathInfoMappings()) {
569: for (PathInfoMapping mapping : element
570: .getPathInfoMappings()) {
571: Matcher matcher = mapping.getRegexp().matcher(
572: pathinfo);
573: if (matcher.matches()) {
574: return element;
575: }
576: }
577: }
578: }
579: }
580:
581: // return the first element that handles the url and doesn't have
582: // any pathinfo mappings
583: for (ElementInfo element : elements) {
584: if (!element.hasPathInfoMappings()
585: || PathInfoMode.LOOSE.equals(element
586: .getPathInfoMode())) {
587: return element;
588: }
589: }
590:
591: return null;
592: }
593:
594: /**
595: * Retrieves the collection of all the URLs that are present in this site.
596: *
597: * @return the collection of all the URLs in this site
598: * @since 1.0
599: */
600: public Collection<String> getUrls() {
601: if (null == mData.mUrls) {
602: ArrayList urls = new ArrayList<String>(mData.mUrlMapping
603: .keySet());
604: urls.addAll(mData.mPathinfoUrlMapping.keySet());
605: mData.mUrls = urls;
606: }
607:
608: return mData.mUrls;
609: }
610:
611: /**
612: * Indicates whether an absolute element ID is present in the site.
613: *
614: * @param id the absolute element ID that should be looked up
615: * @return <code>true</code> if the element ID could be found; or
616: * <p><code>false</code> otherwise
617: * @since 1.0
618: */
619: public boolean containsId(String id) {
620: if (null == id)
621: throw new IllegalArgumentException("id can't be null.");
622: if (0 == id.length())
623: throw new IllegalArgumentException("id can't be empty.");
624:
625: return mData.mIdMapping.containsKey(id);
626: }
627:
628: /**
629: * Retrieves the element information in this site that corresponds to
630: * provided absolute element ID.
631: *
632: * @param id the absolute element ID that should be looked up
633: * @return the corresponding element information; or
634: * <p><code>null</code> if the absolute element ID couldn't be found
635: * @since 1.0
636: */
637: public ElementInfo resolveId(String id) throws EngineException {
638: return resolveId(id, null);
639: }
640:
641: /**
642: * Retrieves the element information in this site that corresponds to
643: * provided element ID.
644: *
645: * @param id the element ID that should be looked up
646: * @param reference the element information that should be used as a
647: * reference to look up the element information from when a relative ID
648: * is provided
649: * @return the corresponding element information; or
650: * <p><code>null</code> if the element ID couldn't be found
651: * @since 1.0
652: */
653: public ElementInfo resolveId(String id, ElementInfo reference)
654: throws EngineException {
655: if (null == id)
656: throw new IllegalArgumentException("id can't be null.");
657: if (0 == id.length())
658: throw new IllegalArgumentException("id can't be empty.");
659:
660: checkModification();
661:
662: String absolute_id = getCanonicalId(getAbsoluteId(id, reference));
663:
664: return mData.mIdMapping.get(absolute_id);
665: }
666:
667: /**
668: * Transforms the provided element ID into an absolute element ID.
669: *
670: * @param id the element ID that should be transformed
671: * @param reference the element information that should be used as a
672: * reference to look up the element information from when a relative ID
673: * is provided
674: * @return the absolute element ID that corresponds to the provided
675: * element ID
676: * @since 1.0
677: */
678: public static String getAbsoluteId(String id, ElementInfo reference) {
679: if (null == id)
680: throw new IllegalArgumentException("id can't be null.");
681: if (0 == id.length())
682: throw new IllegalArgumentException("id can't be empty.");
683:
684: // resolve a relative element id
685: if (!id.startsWith(".")) {
686: if (null == reference)
687: throw new IllegalArgumentException(
688: "reference can't be null for a relative element id.");
689:
690: String path_id = reference.getReferenceId().substring(0,
691: reference.getReferenceId().lastIndexOf(".") + 1);
692: StringBuilder absolute_id = new StringBuilder(path_id);
693: absolute_id.append(id);
694: id = absolute_id.toString();
695: }
696:
697: return id;
698: }
699:
700: /**
701: * Transforms the provided element ID into a canonical ID without any
702: * parent indicators.
703: *
704: * @param id the element ID that should be transformed
705: * @return the canonical element ID that corresponds to the provided
706: * element ID
707: * @since 1.0
708: */
709: public static String getCanonicalId(String id) {
710: if (null == id) {
711: return null;
712: }
713:
714: StringBuilder canonical_id = new StringBuilder();
715:
716: StringTokenizer id_tok = new StringTokenizer(id, ".^", true);
717: String token = null;
718: int seperator_index = -1;
719: while (id_tok.hasMoreTokens()) {
720: token = id_tok.nextToken();
721: if (token.equals(".")) {
722: // do nothing
723: } else if (token.equals("^")) {
724: // fold back to the previous element path part
725: // and don't go further than an empty string
726: seperator_index = canonical_id.lastIndexOf(".");
727: if (seperator_index != -1) {
728: canonical_id.setLength(seperator_index);
729: }
730: } else {
731: canonical_id.append(".");
732: canonical_id.append(token);
733: }
734: }
735:
736: // handle arrival elements
737: if (id.endsWith(".")) {
738: canonical_id.append(".");
739: }
740:
741: return canonical_id.toString();
742: }
743:
744: /**
745: * Adds the specified listener to receive site-related events.
746: * If <code>listener</code> is null, no exception is thrown and no action
747: * is performed.
748: *
749: * @param listener The site listener that will be added.
750: * @see SiteListener
751: * @see #removeListener(SiteListener)
752: * @since 1.5
753: */
754: public void addListener(SiteListener listener) {
755: if (null == listener)
756: return;
757:
758: if (null == mListeners) {
759: mListeners = new HashSet<SiteListener>();
760: }
761: mListeners.add(listener);
762: }
763:
764: /**
765: * Removes the site listener so that it no longer receives any events. This
766: * method performs no function, nor does it throw an exception if the listener
767: * specified by the argument was not previously added to this component or is
768: * <code>null</code>.
769: *
770: * @param listener The site listener that will be removed.
771: * @see SiteListener
772: * @see #addListener(SiteListener)
773: * @since 1.5
774: */
775: public void removeListener(SiteListener listener) {
776: if (mListeners != null) {
777: mListeners.remove(listener);
778: }
779: }
780:
781: /**
782: * Notifies the registered listeners that one of the site's resources has
783: * been detected as being modified.
784: *
785: * @see SiteListener
786: * @since 1.5
787: */
788: public void fireModified() {
789: if (mListeners != null && mListeners.size() > 0) {
790: for (SiteListener listener : mListeners) {
791: listener.modified(this );
792: }
793: }
794: }
795:
796: Map<String, Method> getCachedOutputGetters(String elementId) {
797: return mData.mOutputGettersCache.get(elementId);
798: }
799:
800: void putCachedOutputGetters(String elementId,
801: Map<String, Method> outputGetters) {
802: synchronized (mData) {
803: mData.mOutputGettersCache.put(elementId, outputGetters);
804: }
805: }
806:
807: Map<String, Method> getCachedOutbeanGetters(String elementId) {
808: return mData.mOutbeanGettersCache.get(elementId);
809: }
810:
811: void putCachedOutbeanGetters(String elementId,
812: Map<String, Method> outbeanGetters) {
813: synchronized (mData) {
814: mData.mOutbeanGettersCache.put(elementId, outbeanGetters);
815: }
816: }
817:
818: Map<String, Method> getCachedOutcookieGetters(String elementId) {
819: return mData.mOutcookieGettersCache.get(elementId);
820: }
821:
822: void putCachedOutcookieGetters(String elementId,
823: Map<String, Method> outcookieGetters) {
824: synchronized (mData) {
825: mData.mOutcookieGettersCache.put(elementId,
826: outcookieGetters);
827: }
828: }
829:
830: Map<String, Method> getCachedPropertySetters(String elementId) {
831: return mData.mPropertySettersCache.get(elementId);
832: }
833:
834: void putCachedPropertySetters(String elementId,
835: Map<String, Method> propertySetters) {
836: synchronized (mData) {
837: mData.mPropertySettersCache.put(elementId, propertySetters);
838: }
839: }
840:
841: Map<String, Method> getCachedIncookieSetters(String elementId) {
842: return mData.mIncookieSettersCache.get(elementId);
843: }
844:
845: void putCachedIncookieSetters(String elementId,
846: Map<String, Method> incookieSetters) {
847: synchronized (mData) {
848: mData.mIncookieSettersCache.put(elementId, incookieSetters);
849: }
850: }
851:
852: Map<String, Method> getCachedInputSetters(String elementId) {
853: return mData.mInputSettersCache.get(elementId);
854: }
855:
856: void putCachedInputSetters(String elementId,
857: Map<String, Method> inputSetters) {
858: synchronized (mData) {
859: mData.mInputSettersCache.put(elementId, inputSetters);
860: }
861: }
862:
863: Map<String, Method> getCachedInbeanSetters(String elementId) {
864: return mData.mInbeanSettersCache.get(elementId);
865: }
866:
867: void putCachedInbeanSetters(String elementId,
868: Map<String, Method> inbeanSetters) {
869: synchronized (mData) {
870: mData.mInbeanSettersCache.put(elementId, inbeanSetters);
871: }
872: }
873:
874: SubmissionSettersCache getSubmissionSettersCache(String elementId) {
875: return mData.mSubmissionSettersCache.get(elementId);
876: }
877:
878: void putSubmissionSettersCache(String elementId,
879: SubmissionSettersCache submissionSettersCache) {
880: synchronized (mData) {
881: mData.mSubmissionSettersCache.put(elementId,
882: submissionSettersCache);
883: }
884: }
885:
886: private class SiteData {
887: private Map<String, ElementInfo> mUrlMapping = new LinkedHashMap<String, ElementInfo>();
888: private Map<String, List<ElementInfo>> mPathinfoUrlMapping = new LinkedHashMap<String, List<ElementInfo>>();
889: private List<String> mUrls = null;
890:
891: private Map<String, ElementInfo> mFallbackUrlMapping = new HashMap<String, ElementInfo>();
892: private Map<String, ElementInfo> mIdMapping = new LinkedHashMap<String, ElementInfo>();
893: private ContinuationManager<ElementSupport> mContinuationManager = new ContinuationManager<ElementSupport>(
894: EngineContinuationConfigRuntimeSingleton.INSTANCE);
895:
896: private ResourceFinder mResourceFinder = null;
897: private HashMap<UrlResource, Long> mResourceModificationTimes = null;
898:
899: private Map<String, Map<String, Method>> mOutputGettersCache;
900: private Map<String, Map<String, Method>> mOutbeanGettersCache;
901: private Map<String, Map<String, Method>> mOutcookieGettersCache;
902:
903: private Map<String, Map<String, Method>> mPropertySettersCache;
904: private Map<String, Map<String, Method>> mIncookieSettersCache;
905: private Map<String, Map<String, Method>> mInputSettersCache;
906: private Map<String, Map<String, Method>> mInbeanSettersCache;
907: private Map<String, SubmissionSettersCache> mSubmissionSettersCache;
908:
909: SiteData() {
910: clearCaches();
911: }
912:
913: void clearCaches() {
914: if (TerracottaUtils.isTcPresent()) {
915:
916: mOutputGettersCache = new HashMap<String, Map<String, Method>>();
917: mOutbeanGettersCache = new HashMap<String, Map<String, Method>>();
918: mOutcookieGettersCache = new HashMap<String, Map<String, Method>>();
919:
920: mPropertySettersCache = new HashMap<String, Map<String, Method>>();
921: mIncookieSettersCache = new HashMap<String, Map<String, Method>>();
922: mInputSettersCache = new HashMap<String, Map<String, Method>>();
923: mInbeanSettersCache = new HashMap<String, Map<String, Method>>();
924: mSubmissionSettersCache = new HashMap<String, SubmissionSettersCache>();
925: } else {
926: mOutputGettersCache = new WeakHashMap<String, Map<String, Method>>();
927: mOutbeanGettersCache = new WeakHashMap<String, Map<String, Method>>();
928: mOutcookieGettersCache = new WeakHashMap<String, Map<String, Method>>();
929:
930: mPropertySettersCache = new WeakHashMap<String, Map<String, Method>>();
931: mIncookieSettersCache = new WeakHashMap<String, Map<String, Method>>();
932: mInputSettersCache = new WeakHashMap<String, Map<String, Method>>();
933: mInbeanSettersCache = new WeakHashMap<String, Map<String, Method>>();
934: mSubmissionSettersCache = new WeakHashMap<String, SubmissionSettersCache>();
935: }
936: }
937: }
938: }
939:
940: class SubmissionSettersCache {
941: private Map<String, Map<String, Method>> mSubmissionparamSettersCache = new HashMap<String, Map<String, Method>>();
942: private Map<String, Map<String, Method>> mSubmissionbeanSettersCache = new HashMap<String, Map<String, Method>>();
943: private Map<String, Map<String, Method>> mUploadedfileSettersCache = new HashMap<String, Map<String, Method>>();
944:
945: Map<String, Method> getCachedSubmissionparamSetters(
946: String submissionName) {
947: return mSubmissionparamSettersCache.get(submissionName);
948: }
949:
950: synchronized void putCachedSubmissionparamSetters(
951: String submissionName,
952: Map<String, Method> submissionparamSetters) {
953: mSubmissionparamSettersCache.put(submissionName,
954: submissionparamSetters);
955: }
956:
957: Map<String, Method> getCachedSubmissionbeanSetters(
958: String submissionName) {
959: return mSubmissionbeanSettersCache.get(submissionName);
960: }
961:
962: synchronized void putCachedSubmissionbeanSetters(
963: String submissionName,
964: Map<String, Method> submissionbeanSetters) {
965: mSubmissionbeanSettersCache.put(submissionName,
966: submissionbeanSetters);
967: }
968:
969: Map<String, Method> getCachedUploadedfileSetters(
970: String submissionName) {
971: return mUploadedfileSettersCache.get(submissionName);
972: }
973:
974: synchronized void putCachedUploadedfileSetters(
975: String submissionName,
976: Map<String, Method> uploadedfileSetters) {
977: mUploadedfileSettersCache.put(submissionName,
978: uploadedfileSetters);
979: }
980: }
|