0001: /*
0002: * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
0003: * Distributed under the terms of either:
0004: * - the common development and distribution license (CDDL), v1.0; or
0005: * - the GNU Lesser General Public License, v2.1 or later
0006: * $Id
0007: */
0008: package com.uwyn.rife.engine;
0009:
0010: import com.uwyn.rife.engine.exceptions.*;
0011: import java.util.*;
0012:
0013: import com.uwyn.rife.config.RifeConfig;
0014: import com.uwyn.rife.engine.elements.Redirect;
0015: import com.uwyn.rife.ioc.HierarchicalProperties;
0016: import com.uwyn.rife.ioc.PropertyValue;
0017: import com.uwyn.rife.ioc.exceptions.PropertyValueException;
0018: import com.uwyn.rife.rep.Rep;
0019: import com.uwyn.rife.resources.ResourceFinder;
0020: import com.uwyn.rife.resources.ResourceFinderClasspath;
0021: import com.uwyn.rife.site.Constrained;
0022: import com.uwyn.rife.site.ConstrainedUtils;
0023: import com.uwyn.rife.site.ValidatedConstrained;
0024: import com.uwyn.rife.site.ValidationGroup;
0025: import com.uwyn.rife.tools.BeanUtils;
0026: import com.uwyn.rife.tools.FileUtils;
0027: import com.uwyn.rife.tools.StringUtils;
0028: import com.uwyn.rife.tools.exceptions.BeanUtilsException;
0029:
0030: public class SiteBuilder {
0031: private ResourceFinder mResourceFinder = null;
0032: private SiteBuilder mParent = null;
0033: private SubsiteDeclaration mSubsiteDeclaration = null;
0034:
0035: private boolean mProcessed = false;
0036: private String mIdentifier = null;
0037: private String mDeclarationName = null;
0038: private String mSiteId = null;
0039: private String mUrlPrefix = null;
0040: private Stack<StateStore> mStateStores = null;
0041: private HashSet<String> mSubsiteHistory = null;
0042:
0043: private Site mSite = null;
0044:
0045: private Stack<GroupDeclaration> mGroupDeclarationsStack = null;
0046: private ArrayList<GroupDeclaration> mGroupDeclarations = null;
0047:
0048: private String mFallbackElementId = null;
0049: private String mArrivalElementId = null;
0050: private boolean mArrivalRedirect = false;
0051: private ElementDeclaration mArrivalElementDeclaration = null;
0052: private ArrayList<String> mDepartureIds = null;
0053:
0054: private LinkedHashMap<String, ElementDeclaration> mElementIdMapping = null;
0055: private ArrayList<ElementDeclaration> mElementDeclarations = null;
0056:
0057: private LinkedHashMap<String, SubsiteDeclaration> mChildSubsiteIdMapping = null;
0058: private ArrayList<SubsiteDeclaration> mChildSubsiteDeclarations = null;
0059:
0060: private LinkedHashMap<String, HashSet<DataLinkDeclaration>> mDataLinkMapping = null;
0061: private LinkedHashMap<String, HashSet<FlowLinkDeclaration>> mFlowLinkMapping = null;
0062: private LinkedHashMap<String, HashSet<AutoLinkDeclaration>> mAutoLinkMapping = null;
0063:
0064: private HierarchicalProperties mProperties = null;
0065:
0066: public SiteBuilder(String declarationName) {
0067: this (declarationName, ResourceFinderClasspath.getInstance());
0068: }
0069:
0070: public SiteBuilder(String declarationName,
0071: ResourceFinder resourceFinder) {
0072: if (null == declarationName)
0073: throw new IllegalArgumentException(
0074: "declarationName can't be null.");
0075: if (null == resourceFinder)
0076: throw new IllegalArgumentException(
0077: "resourceFinder can't be null.");
0078:
0079: mResourceFinder = resourceFinder;
0080:
0081: initialize(declarationName);
0082: }
0083:
0084: private SiteBuilder(String declarationName,
0085: ResourceFinder resourceFinder, SiteBuilder parent,
0086: SubsiteDeclaration subsite) {
0087: assert declarationName != null;
0088: assert resourceFinder != null;
0089: assert parent != null;
0090: assert parent != this ;
0091: assert subsite != null;
0092:
0093: mResourceFinder = resourceFinder;
0094: mParent = parent;
0095: mSubsiteDeclaration = subsite;
0096:
0097: initialize(declarationName);
0098: }
0099:
0100: private SiteBuilder initialize(String declarationName) {
0101: mDeclarationName = declarationName;
0102:
0103: if (null == getParent()) {
0104: mSite = new Site();
0105: mSite.setDeclarationName(mDeclarationName);
0106:
0107: // if the site structure must be automatically reloaded
0108: // ensure that the same resource finder is used as the one
0109: // that found the element and site xml files
0110: if (RifeConfig.Engine.getSiteAutoReload()) {
0111: mSite.setResourceFinder(mResourceFinder);
0112: }
0113:
0114: mStateStores = new Stack<StateStore>();
0115: mStateStores.push(StateStoreFactory
0116: .getInstance(StateStoreQuery.IDENTIFIER));
0117: mGroupDeclarationsStack = new Stack<GroupDeclaration>();
0118: mGroupDeclarations = new ArrayList<GroupDeclaration>();
0119: mSubsiteHistory = new HashSet<String>();
0120:
0121: addGroupDeclaration(new GroupDeclaration(this ,
0122: declarationName));
0123: } else {
0124: mSite = mParent.mSite;
0125:
0126: mStateStores = mSubsiteDeclaration.getStateStores();
0127: mSubsiteHistory = new HashSet<String>(
0128: getParent().mSubsiteHistory);
0129:
0130: mGroupDeclarationsStack = new Stack<GroupDeclaration>();
0131: mGroupDeclarations = new ArrayList<GroupDeclaration>();
0132:
0133: addGroupDeclaration(mSubsiteDeclaration
0134: .getGroupDeclaration());
0135: }
0136:
0137: mFallbackElementId = null;
0138: mArrivalElementId = null;
0139: mArrivalElementDeclaration = null;
0140: mDepartureIds = new ArrayList<String>();
0141: mElementIdMapping = new LinkedHashMap<String, ElementDeclaration>();
0142: mElementDeclarations = new ArrayList<ElementDeclaration>();
0143: mChildSubsiteIdMapping = new LinkedHashMap<String, SubsiteDeclaration>();
0144: mChildSubsiteDeclarations = new ArrayList<SubsiteDeclaration>();
0145: mDataLinkMapping = new LinkedHashMap<String, HashSet<DataLinkDeclaration>>();
0146: mFlowLinkMapping = new LinkedHashMap<String, HashSet<FlowLinkDeclaration>>();
0147: mAutoLinkMapping = new LinkedHashMap<String, HashSet<AutoLinkDeclaration>>();
0148: mProperties = new HierarchicalProperties();
0149: // if this is the root site, the parent properties are those
0150: // of the repository
0151: if (null == mParent) {
0152: mProperties.setParent(Rep.getProperties());
0153: } else {
0154: // the root site hasn't got a subsite declaration, so link
0155: // to its properties directly
0156: if (null == mParent.getSubsiteDeclaration()) {
0157: mProperties.setParent(mParent.getProperties());
0158: }
0159: // for the real subsite, the parent should be the declaration properties
0160: // since they have precedence over the subsite properties themselves
0161: else {
0162: mProperties.setParent(mParent.getSubsiteDeclaration()
0163: .getProperties());
0164: }
0165: }
0166:
0167: return this ;
0168: }
0169:
0170: public synchronized Site getSite() {
0171: SiteBuilder root = getRoot();
0172: if (!mProcessed) {
0173: root.process();
0174: }
0175:
0176: return root.mSite;
0177: }
0178:
0179: public String getSiteProcessorIdentifier() {
0180: return mIdentifier;
0181: }
0182:
0183: private synchronized void process() throws EngineException {
0184: String declaration = mDeclarationName;
0185: SiteProcessorFactory processor_factory = null;
0186:
0187: String identifier = SiteProcessorFactory.MANUAL_IDENTIFIER;
0188: int identifier_index = mDeclarationName.indexOf(":");
0189: int extension_index = mDeclarationName.lastIndexOf(".");
0190: if (identifier_index != -1) {
0191: identifier = mDeclarationName
0192: .substring(0, identifier_index);
0193: declaration = mDeclarationName
0194: .substring(identifier_index + 1);
0195:
0196: processor_factory = SiteProcessorFactory
0197: .getSiteProcessorFactory(identifier);
0198: } else if (extension_index != -1) {
0199: String extension = mDeclarationName
0200: .substring(extension_index + 1);
0201: Collection<SiteProcessorFactory> factories = SiteProcessorFactory
0202: .getSiteProcessorFactories();
0203: for (SiteProcessorFactory factory : factories) {
0204: if (factory.getExtension() != null
0205: && factory.getExtension().equals(extension)) {
0206: processor_factory = factory;
0207: break;
0208: }
0209: }
0210:
0211: if (null == processor_factory) {
0212: throw new SiteProcessorExtensionUnsupportedException(
0213: mDeclarationName, extension);
0214: }
0215: } else {
0216: processor_factory = SiteProcessorFactory
0217: .getSiteProcessorFactory(identifier);
0218: }
0219:
0220: if (null == processor_factory) {
0221: throw new SiteProcessorIdentifierUnsupportedException(
0222: mDeclarationName, identifier);
0223: }
0224:
0225: // check for circular subsites
0226: if (!identifier.equals(SiteProcessorFactory.MANUAL_IDENTIFIER)) {
0227: if (mSubsiteHistory.contains(mDeclarationName)) {
0228: throw new CircularSubsitesException(mDeclarationName);
0229: }
0230: mSubsiteHistory.add(mDeclarationName);
0231: }
0232:
0233: // process the site definition
0234: SiteProcessor processor = processor_factory.getProcessor();
0235: if (processor != null) {
0236: processor.processSite(this , declaration, mResourceFinder);
0237: }
0238:
0239: mIdentifier = processor_factory.getIdentifier();
0240: finish();
0241:
0242: mProcessed = true;
0243: }
0244:
0245: private synchronized void finish() throws EngineException {
0246: // first gather all the data about the elements and the subsites
0247: setupData();
0248:
0249: if (null == getParent()) {
0250: // process the collected data from the root upwards to ensure
0251: // that all elements have been declared before the links to them
0252: // are processed
0253: processData();
0254:
0255: // create the inheritance stacks from the root site upwards
0256: // otherwise they would be created before all the subsites are
0257: // completely defined
0258: createInheritanceStacks();
0259:
0260: // create the precedence stacks from the root site upwards
0261: // otherwise they would be created before all the subsites are
0262: // completely defined
0263: createPrecedenceStacks();
0264: }
0265: }
0266:
0267: public SiteBuilder setFallback(String fallbackElementId) {
0268: mFallbackElementId = ensureLocalElementId(fallbackElementId);
0269:
0270: return this ;
0271: }
0272:
0273: public SubsiteDeclaration enterSubsiteDeclaration(
0274: String declarationName) throws EngineException {
0275: // auto-generate empty declaration names
0276: if (null == declarationName) {
0277: declarationName = SiteProcessorFactory.MANUAL_IDENTIFIER
0278: + ":" + getDeclarationName() + ":subsite"
0279: + (mChildSubsiteDeclarations.size() + 1);
0280: }
0281:
0282: GroupDeclaration group_declaration = new GroupDeclaration(this ,
0283: declarationName, getCurrentGroupDeclaration());
0284: SubsiteDeclaration subsite_declaration = new SubsiteDeclaration(
0285: declarationName, group_declaration, mStateStores);
0286: mChildSubsiteDeclarations.add(subsite_declaration);
0287: SiteBuilder builder = new SiteBuilder(subsite_declaration
0288: .getDeclarationName(), mResourceFinder, this ,
0289: subsite_declaration);
0290: subsite_declaration.setSiteBuilder(builder);
0291: group_declaration.setActiveSiteBuilder(builder);
0292:
0293: return subsite_declaration;
0294: }
0295:
0296: public SubsiteDeclaration leaveSubsite() {
0297: if (null == mParent) {
0298: return null;
0299: }
0300:
0301: return mSubsiteDeclaration;
0302: }
0303:
0304: public SiteBuilder enterGroup() throws EngineException {
0305: addGroupDeclaration(new GroupDeclaration(this ,
0306: mDeclarationName, getCurrentGroupDeclaration()));
0307:
0308: return this ;
0309: }
0310:
0311: public SiteBuilder leaveGroup() throws EngineException {
0312: mGroupDeclarationsStack.pop();
0313:
0314: return this ;
0315: }
0316:
0317: public SiteBuilder setInherits(String inherits)
0318: throws EngineException {
0319: getCurrentGroupDeclaration().setInherits(inherits);
0320:
0321: return this ;
0322: }
0323:
0324: public SiteBuilder setPre(String pre) throws EngineException {
0325: getCurrentGroupDeclaration().setPre(pre);
0326:
0327: return this ;
0328: }
0329:
0330: public SiteBuilder addGlobalBean(String classname) {
0331: return addGlobalBean(classname, null, null, null);
0332: }
0333:
0334: public SiteBuilder addGlobalBean(String classname, String prefix) {
0335: return addGlobalBean(classname, prefix, null, null);
0336: }
0337:
0338: public SiteBuilder addGlobalBean(String classname, String prefix,
0339: String name) {
0340: return addGlobalBean(classname, prefix, name, null);
0341: }
0342:
0343: public SiteBuilder addGlobalBean(String classname, String prefix,
0344: String name, String groupName) throws EngineException {
0345: BeanDeclaration bean_declaration = new BeanDeclaration(
0346: classname, prefix, groupName);
0347:
0348: return addGlobalBean(bean_declaration, name);
0349: }
0350:
0351: public SiteBuilder addGlobalBean(Class klass) {
0352: return addGlobalBean(klass, null, null, null);
0353: }
0354:
0355: public SiteBuilder addGlobalBean(Class klass, String prefix) {
0356: return addGlobalBean(klass, prefix, null, null);
0357: }
0358:
0359: public SiteBuilder addGlobalBean(Class klass, String prefix,
0360: String name) {
0361: return addGlobalBean(klass, prefix, name, null);
0362: }
0363:
0364: public SiteBuilder addGlobalBean(Class klass, String prefix,
0365: String name, String groupName) throws EngineException {
0366: BeanDeclaration bean_declaration = new BeanDeclaration(klass,
0367: prefix, groupName);
0368:
0369: return addGlobalBean(bean_declaration, name);
0370: }
0371:
0372: private SiteBuilder addGlobalBean(BeanDeclaration beanDeclaration,
0373: String name) throws EngineException {
0374: GroupDeclaration site_group = getCurrentGroupDeclaration();
0375: try {
0376: Class bean_class = beanDeclaration.getBeanClass();
0377:
0378: if (name != null) {
0379: site_group.addNamedGlobalBean(name, beanDeclaration);
0380: }
0381:
0382: try {
0383: Object instance = bean_class.newInstance();
0384: Constrained constrained = ConstrainedUtils
0385: .makeConstrainedInstance(instance);
0386: Set<String> properties;
0387: if (beanDeclaration.getGroupName() != null) {
0388: if (!(instance instanceof ValidatedConstrained)) {
0389: throw new GlobalBeanGroupRequiresValidatedConstrainedException(
0390: mDeclarationName, beanDeclaration
0391: .getClassname(),
0392: beanDeclaration.getGroupName());
0393: }
0394:
0395: ValidatedConstrained validation = (ValidatedConstrained) instance;
0396: ValidationGroup group = validation
0397: .getGroup(beanDeclaration.getGroupName());
0398: if (null == group) {
0399: throw new GlobalBeanGroupNotFoundException(
0400: mDeclarationName, beanDeclaration
0401: .getClassname(),
0402: beanDeclaration.getGroupName());
0403: }
0404: properties = new TreeSet<String>();
0405: if (null == beanDeclaration.getPrefix()) {
0406: properties.addAll(group.getPropertyNames());
0407: } else {
0408: for (String property_name : (List<String>) group
0409: .getPropertyNames()) {
0410: properties.add(beanDeclaration.getPrefix()
0411: + property_name);
0412: }
0413: }
0414: } else {
0415: properties = BeanUtils.getPropertyNames(bean_class,
0416: null, null, beanDeclaration.getPrefix());
0417: }
0418:
0419: for (String property : properties) {
0420: if (ConstrainedUtils.editConstrainedProperty(
0421: constrained, property, beanDeclaration
0422: .getPrefix())) {
0423: site_group.addGlobalVar(property,
0424: new GlobalVar(null));
0425: }
0426: }
0427: } catch (IllegalAccessException e) {
0428: throw new GlobalBeanErrorException(mDeclarationName,
0429: beanDeclaration.getClassname(), e);
0430: } catch (InstantiationException e) {
0431: throw new GlobalBeanErrorException(mDeclarationName,
0432: beanDeclaration.getClassname(), e);
0433: } catch (BeanUtilsException e) {
0434: throw new GlobalBeanErrorException(mDeclarationName,
0435: beanDeclaration.getClassname(), e);
0436: }
0437: } catch (ClassNotFoundException e) {
0438: throw new GlobalBeanNotFoundException(mDeclarationName,
0439: beanDeclaration.getClassname(), e);
0440: }
0441:
0442: return this ;
0443: }
0444:
0445: public SiteBuilder addGlobalExit(String name, String destId)
0446: throws EngineException {
0447: return addGlobalExit(name, destId, false, false, false, false,
0448: false, false);
0449: }
0450:
0451: public SiteBuilder addReflectiveGlobalExit(String name)
0452: throws EngineException {
0453: return addGlobalExit(name, null, true, false, false, false,
0454: false, false);
0455: }
0456:
0457: public SiteBuilder addSnapbackGlobalExit(String name)
0458: throws EngineException {
0459: return addGlobalExit(name, null, false, true, false, false,
0460: false, false);
0461: }
0462:
0463: public SiteBuilder addRedirectGlobalExit(String name)
0464: throws EngineException {
0465: return addGlobalExit(name, null, false, false, false, false,
0466: true, false);
0467: }
0468:
0469: public SiteBuilder addGlobalExit(String name, String destId,
0470: boolean reflective, boolean snapback,
0471: boolean cancelInheritance, boolean cancelEmbedding,
0472: boolean redirect, boolean cancelContinuations)
0473: throws EngineException {
0474: if (null == destId && !reflective && !snapback) {
0475: throw new GlobalExitTargetRequiredException(
0476: mDeclarationName, name);
0477: }
0478: if (null == destId && reflective && snapback) {
0479: throw new GlobalExitAmbiguousTargetException(
0480: mDeclarationName, name);
0481: }
0482: if (destId != null && (reflective || snapback)) {
0483: throw new GlobalExitAmbiguousTargetException(
0484: mDeclarationName, name);
0485: }
0486:
0487: GlobalExit globalexit = new GlobalExit(destId, reflective,
0488: snapback, cancelInheritance, cancelEmbedding, redirect,
0489: cancelContinuations);
0490: getCurrentGroupDeclaration().addGlobalExit(name, globalexit);
0491:
0492: return this ;
0493: }
0494:
0495: public SiteBuilder setArrival(String destId) throws EngineException {
0496: return setArrival(destId, false);
0497: }
0498:
0499: public SiteBuilder setArrival(String destId, boolean redirect)
0500: throws EngineException {
0501: mArrivalElementId = ensureLocalElementId(destId);
0502: mArrivalRedirect = redirect;
0503:
0504: return this ;
0505: }
0506:
0507: public SiteBuilder addDeparture(String srcId)
0508: throws EngineException {
0509: mDepartureIds.add(ensureLocalElementId(srcId));
0510:
0511: return this ;
0512: }
0513:
0514: public SiteBuilder enterState(String store) throws EngineException {
0515: StateStore state_store = StateStoreFactory.getInstance(store);
0516: if (null == state_store) {
0517: throw new StateStoreUnknownException(mDeclarationName,
0518: store);
0519: }
0520:
0521: mStateStores.push(state_store);
0522:
0523: return this ;
0524: }
0525:
0526: public SiteBuilder leaveState() throws EngineException {
0527: mStateStores.pop();
0528:
0529: return this ;
0530: }
0531:
0532: public ElementInfoBuilder enterElement() throws EngineException {
0533: return enterElement(null);
0534: }
0535:
0536: public ElementInfoBuilder enterElement(String declarationName)
0537: throws EngineException {
0538: ElementDeclaration declaration = new ElementDeclaration(this ,
0539: mResourceFinder, getCurrentGroupDeclaration(),
0540: mStateStores.peek(), declarationName);
0541: addElementDeclaration(declaration);
0542:
0543: return declaration.getElementInfoBuilder();
0544: }
0545:
0546: public SiteBuilder addGlobalVar(String name) throws EngineException {
0547: return addGlobalVar(name, null);
0548: }
0549:
0550: public SiteBuilder addGlobalVar(String name, String[] defaultValues)
0551: throws EngineException {
0552: getCurrentGroupDeclaration().addGlobalVar(name,
0553: new GlobalVar(defaultValues));
0554:
0555: return this ;
0556: }
0557:
0558: public SiteBuilder addGlobalCookie(String name)
0559: throws EngineException {
0560: return addGlobalCookie(name, null);
0561: }
0562:
0563: public SiteBuilder addGlobalCookie(String name, String defaultValue)
0564: throws EngineException {
0565: getCurrentGroupDeclaration()
0566: .addGlobalCookie(name, defaultValue);
0567:
0568: return this ;
0569: }
0570:
0571: public SiteBuilder addProperty(String name, PropertyValue value) {
0572: mProperties.put(name, value);
0573:
0574: return this ;
0575: }
0576:
0577: public HierarchicalProperties getProperties() {
0578: return mProperties;
0579: }
0580:
0581: public boolean containsProperty(String name) {
0582: if (null == mSubsiteDeclaration) {
0583: return mProperties.contains(name);
0584: } else {
0585: return mSubsiteDeclaration.getProperties().contains(name);
0586: }
0587: }
0588:
0589: public Object getProperty(String name) {
0590: return getProperty(name, null);
0591: }
0592:
0593: public Object getProperty(String name, Object defaultValue) {
0594: PropertyValue property = _getProperty(name);
0595:
0596: Object result = null;
0597:
0598: if (property != null) {
0599: try {
0600: result = property.getValue();
0601: } catch (PropertyValueException e) {
0602: throw new PropertyValueRetrievalException(
0603: getDeclarationName(), name, e);
0604: }
0605: }
0606:
0607: if (null == result) {
0608: return defaultValue;
0609: }
0610:
0611: return result;
0612: }
0613:
0614: private PropertyValue _getProperty(String name) {
0615: if (null == mSubsiteDeclaration) {
0616: return mProperties.get(name);
0617: } else {
0618: return mSubsiteDeclaration.getProperties().get(name);
0619: }
0620: }
0621:
0622: public String getPropertyString(String name) {
0623: return getPropertyString(name, null);
0624: }
0625:
0626: public String getPropertyString(String name, String defaultValue) {
0627: PropertyValue property = _getProperty(name);
0628:
0629: String result = null;
0630:
0631: if (property != null) {
0632: try {
0633: result = property.getValueString();
0634: } catch (PropertyValueException e) {
0635: throw new PropertyValueRetrievalException(
0636: getDeclarationName(), name, e);
0637: }
0638: }
0639:
0640: if (null == result || 0 == result.length()) {
0641: return defaultValue;
0642: }
0643:
0644: return result;
0645: }
0646:
0647: public boolean isPropertyEmpty(String name) throws EngineException {
0648: if (!containsProperty(name)) {
0649: return true;
0650: }
0651:
0652: if (0 == getPropertyString(name, "").length()) {
0653: return true;
0654: }
0655:
0656: return false;
0657: }
0658:
0659: private SiteBuilder addGroupDeclaration(
0660: GroupDeclaration groupDeclaration) {
0661: mGroupDeclarationsStack.push(groupDeclaration);
0662: mGroupDeclarations.add(groupDeclaration);
0663:
0664: return this ;
0665: }
0666:
0667: private void addElementDeclaration(
0668: ElementDeclaration elementDeclaration) {
0669: mElementDeclarations.add(elementDeclaration);
0670: }
0671:
0672: private GroupDeclaration getCurrentGroupDeclaration() {
0673: return mGroupDeclarationsStack.peek();
0674: }
0675:
0676: private String getId() {
0677: if (mSiteId != null) {
0678: return mSiteId;
0679: }
0680:
0681: if (null == mParent) {
0682: mSiteId = ".";
0683: } else {
0684: mSiteId = getParent().getId() + mSubsiteDeclaration.getId()
0685: + ".";
0686: }
0687:
0688: return mSiteId;
0689: }
0690:
0691: private SiteBuilder getRoot() {
0692: SiteBuilder current = this ;
0693: while (current.getParent() != null) {
0694: current = current.getParent();
0695: }
0696:
0697: return current;
0698: }
0699:
0700: SiteBuilder getParent() {
0701: return mParent;
0702: }
0703:
0704: private Collection<ElementDeclaration> getElementDeclarations() {
0705: return mElementDeclarations;
0706: }
0707:
0708: public SubsiteDeclaration getSubsiteDeclaration() {
0709: return mSubsiteDeclaration;
0710: }
0711:
0712: private ElementDeclaration getArrival() {
0713: return mArrivalElementDeclaration;
0714: }
0715:
0716: ElementDeclaration getGlobalElementDeclaration(String id) {
0717: assert id != null;
0718:
0719: // relative element id
0720: if (!id.startsWith(".")) {
0721: id = getId() + id;
0722: }
0723:
0724: id = Site.getCanonicalId(id);
0725:
0726: // obtain the different parts of the id string
0727: ArrayList<String> id_parts = StringUtils.split(id, ".");
0728: int id_part_counter = 0;
0729: SiteBuilder current_site = getRoot();
0730:
0731: id_parts.remove(0); // remove the first entry since it is empty (id starts with a dot)
0732: for (String id_part : id_parts) {
0733: id_part_counter++;
0734:
0735: // check if this is the last id part, only handle elements
0736: // in the last id part, the rest must be subsite ids
0737: // it's possible though that elements are injected in subsites
0738: // from a parent subsite by specifying the dot-seperate path
0739: // directly
0740: if (id_part_counter < id_parts.size()) {
0741: String element_injection = id.substring(current_site
0742: .getId().length());
0743: if (current_site.mElementIdMapping
0744: .containsKey(element_injection)) {
0745: return current_site.mElementIdMapping
0746: .get(element_injection);
0747: }
0748:
0749: // check if the next path matches a subsite
0750: if (current_site.mChildSubsiteIdMapping
0751: .containsKey(id_part)) {
0752: current_site = current_site.mChildSubsiteIdMapping
0753: .get(id_part).getSiteBuilder();
0754: } else {
0755: return null;
0756: }
0757: }
0758: // last id part, thus also look for elements
0759: else {
0760: if (current_site.mElementIdMapping.containsKey(id_part)) {
0761: return current_site.mElementIdMapping.get(id_part);
0762: }
0763:
0764: if (current_site.mChildSubsiteIdMapping
0765: .containsKey(id_part)) {
0766: return current_site.mChildSubsiteIdMapping.get(
0767: id_part).getSiteBuilder().getArrival();
0768: }
0769: }
0770: }
0771:
0772: return null;
0773: }
0774:
0775: private ElementDeclaration getElementDeclaration(String id) {
0776: assert id != null;
0777:
0778: if (mElementIdMapping.containsKey(id)) {
0779: return mElementIdMapping.get(id);
0780: }
0781:
0782: if (mChildSubsiteIdMapping.containsKey(id)) {
0783: return mChildSubsiteIdMapping.get(id).getSiteBuilder()
0784: .getArrival();
0785: }
0786:
0787: return null;
0788: }
0789:
0790: private ElementInfo getElementInfo(String id) {
0791: assert id != null;
0792:
0793: ElementDeclaration element_declaration = getElementDeclaration(id);
0794:
0795: if (element_declaration != null) {
0796: return element_declaration.getElementInfo();
0797: }
0798:
0799: return null;
0800: }
0801:
0802: private void setupElements() {
0803: ElementInfo element_info = null;
0804:
0805: // iterate over the element declarations
0806: for (ElementDeclaration element_declaration : getElementDeclarations()) {
0807: // ensure the unique element id
0808: if (mElementIdMapping.containsKey(element_declaration
0809: .getId())) {
0810: throw new ElementIdAlreadyRegisteredToElementException(
0811: mDeclarationName, element_declaration.getId(),
0812: mElementIdMapping.get(
0813: element_declaration.getId())
0814: .getDeclarationName(),
0815: element_declaration.getDeclarationName());
0816: }
0817: if (mChildSubsiteIdMapping.containsKey(element_declaration
0818: .getId())) {
0819: throw new ElementIdAlreadyRegisteredToSubsiteException(
0820: mDeclarationName, element_declaration.getId(),
0821: mChildSubsiteIdMapping.get(
0822: element_declaration.getId())
0823: .getDeclarationName(),
0824: element_declaration.getDeclarationName());
0825: }
0826:
0827: // process the element directives
0828: ElementInfoBuilder builder = element_declaration
0829: .getElementInfoBuilder();
0830: builder.process();
0831: GroupDeclaration group = element_declaration.getGroup();
0832: element_info = builder.createElementInfo(group
0833: .getGlobalExitsMerged(), group
0834: .getGlobalVarsMerged(), group
0835: .getGlobalCookiesMerged(), group
0836: .getNamedGlobalBeansMerged());
0837: element_info.setGroupId(group.getGroupId());
0838:
0839: // check if the element declation url ends with a wildcard to add
0840: // the support for path info
0841: String element_url = element_declaration.getUrl();
0842:
0843: if (element_url != null) {
0844: if (element_url.endsWith("/")
0845: || 0 == element_url.length()) {
0846: throw new ElementUrlInvalidException(
0847: element_declaration.getId(), element_url);
0848: }
0849:
0850: // ensure an initial slash
0851: if (element_url.length() > 0
0852: && !element_url.startsWith("/")) {
0853: element_url = "/" + element_url;
0854: }
0855:
0856: // prevent double slashes
0857: String url_prefix = getUrlPrefix();
0858: if (url_prefix.endsWith("/")
0859: && element_url.startsWith("/")) {
0860: url_prefix = StringUtils.stripFromEnd(url_prefix,
0861: "/");
0862: element_url = StringUtils.stripFromFront(
0863: element_url, "/");
0864: StringBuilder buffer = new StringBuilder(url_prefix);
0865: buffer.append("/");
0866: buffer.append(element_url);
0867: element_url = buffer.toString();
0868: } else {
0869: element_url = url_prefix + element_url;
0870: }
0871:
0872: // handle path info
0873: if (element_url.endsWith("/*")) {
0874: element_url = element_url.substring(0, element_url
0875: .length() - 2);
0876: element_info.setPathInfoUsed(true);
0877: }
0878: }
0879:
0880: // check if the element has an implementation
0881: if (null == element_info.getImplementation()) {
0882: throw new MissingImplementationException(
0883: element_declaration.getDeclarationName());
0884: }
0885:
0886: // link the element properties with the site properties
0887: HierarchicalProperties site_properties;
0888: if (null == mSubsiteDeclaration) {
0889: site_properties = mProperties;
0890: } else {
0891: site_properties = mSubsiteDeclaration.getProperties();
0892: }
0893: HierarchicalProperties site_properties_shadow = site_properties
0894: .createShadow(Rep.getProperties());
0895:
0896: // deploy and register the constructed element info
0897: element_info.setProperties(element_declaration
0898: .getProperties(), site_properties_shadow);
0899: element_info.setStateStore(element_declaration
0900: .getStateStore());
0901: element_declaration.setElementInfo(element_info);
0902: mSite.addElementInfo(getId() + element_declaration.getId(),
0903: element_info, element_url);
0904: mElementIdMapping.put(element_declaration.getId(),
0905: element_declaration);
0906: element_info.deploy();
0907: }
0908: }
0909:
0910: private void setupSubsites() {
0911: for (SubsiteDeclaration subsite : mChildSubsiteDeclarations) {
0912: SiteBuilder subsite_builder = subsite.getSiteBuilder();
0913:
0914: subsite_builder.process();
0915:
0916: // register the subsite id
0917: if (mElementIdMapping.containsKey(subsite.getId())) {
0918: throw new SubsiteIdAlreadyRegisteredToElementException(
0919: mDeclarationName, subsite.getId(),
0920: mElementIdMapping.get(subsite.getId())
0921: .getDeclarationName(), subsite
0922: .getDeclarationName());
0923: }
0924: if (mChildSubsiteIdMapping.containsKey(subsite.getId())) {
0925: throw new SubsiteIdAlreadyRegisteredToSubsiteException(
0926: mDeclarationName, subsite.getId(),
0927: mChildSubsiteIdMapping.get(subsite.getId())
0928: .getDeclarationName(), subsite
0929: .getDeclarationName());
0930: }
0931:
0932: // register the subsite id
0933: mChildSubsiteIdMapping.put(subsite.getId(), subsite);
0934: }
0935: }
0936:
0937: private void setupArrivalElement() {
0938: if (mArrivalElementId != null) {
0939: mArrivalElementDeclaration = getElementDeclaration(mArrivalElementId);
0940: if (null == mArrivalElementDeclaration) {
0941: elementIdNotFound(mArrivalElementId);
0942: }
0943:
0944: // clone the element declaration and store it in the collection of the
0945: // site's element declarations
0946: mArrivalElementDeclaration = mArrivalElementDeclaration
0947: .clone();
0948: mArrivalElementDeclaration.setId("");
0949: addElementDeclaration(mArrivalElementDeclaration);
0950: mElementIdMapping.put("", mArrivalElementDeclaration);
0951: }
0952: }
0953:
0954: private void processSubsites() {
0955: for (SubsiteDeclaration subsite : mChildSubsiteDeclarations) {
0956: subsite.getSiteBuilder().processData();
0957: }
0958: }
0959:
0960: private void processGlobalExits() {
0961: ElementInfo element_info = null;
0962:
0963: // iterate over all the element declarations in the site
0964: for (ElementDeclaration element_declaration : getElementDeclarations()) {
0965: element_info = element_declaration.getElementInfo();
0966:
0967: // iterate over all global exits of the element
0968: Map<String, GlobalExit> global_exits = element_declaration
0969: .getGroup().getGlobalExitsMerged();
0970: String global_exit_name = null;
0971: GlobalExit global_exit = null;
0972: FlowLink flowlink = null;
0973: for (Map.Entry<String, GlobalExit> global_exit_entry : global_exits
0974: .entrySet()) {
0975: global_exit_name = global_exit_entry.getKey();
0976: global_exit = global_exit_entry.getValue();
0977:
0978: // add the exit to every element info
0979: element_info.addExit(global_exit_name);
0980:
0981: // ensure a flow link from each elementinfo to the target element id
0982: HashSet<FlowLinkDeclaration> flowlinks = mFlowLinkMapping
0983: .get(element_declaration.getId());
0984: if (null == flowlinks) {
0985: flowlinks = new HashSet<FlowLinkDeclaration>();
0986: mFlowLinkMapping.put(element_declaration.getId(),
0987: flowlinks);
0988: }
0989:
0990: // check if this points to a specific element or if it's reflective
0991: if (global_exit.isReflective()) {
0992: flowlink = new FlowLink(global_exit_name,
0993: element_info, global_exit.isSnapback(),
0994: global_exit.cancelInheritance(),
0995: global_exit.cancelEmbedding(), global_exit
0996: .isRedirect(), global_exit
0997: .cancelContinuations());
0998: element_info.setFlowLink(flowlink);
0999:
1000: // check if this element has identical inputs and outputs
1001: // these will be automatically linked due to the reflective exit
1002: Collection<String> input_names = element_info
1003: .getInputNames();
1004: Collection<String> output_names = element_info
1005: .getOutputNames();
1006: DataLinkDeclaration datalink = null;
1007: for (String input_name : input_names) {
1008: if (output_names.contains(input_name)) {
1009: datalink = new DataLinkDeclaration(
1010: input_name, null,
1011: element_declaration.getId(), false,
1012: input_name, null, null);
1013: addDataLink(element_declaration.getId(),
1014: datalink, false);
1015: }
1016: }
1017: } else {
1018: ElementDeclaration target_elementdeclaration = null;
1019:
1020: String globalexit_destid = global_exit.getDestId();
1021: if (globalexit_destid != null) {
1022: // get the element declaration that corresponds to the destination id
1023: target_elementdeclaration = getGlobalElementDeclaration(globalexit_destid);
1024:
1025: // if the target element couldn't be found, throw an exception
1026: if (null == target_elementdeclaration) {
1027: elementIdNotFound(global_exit.getDestId());
1028: }
1029:
1030: global_exit.setTarget(target_elementdeclaration
1031: .getElementInfo());
1032: }
1033:
1034: flowlinks.add(new FlowLinkDeclaration(this ,
1035: global_exit_name, globalexit_destid,
1036: global_exit.isSnapback(), global_exit
1037: .cancelInheritance(), global_exit
1038: .cancelEmbedding(), global_exit
1039: .isRedirect(), global_exit
1040: .cancelContinuations()));
1041: }
1042: }
1043: }
1044: }
1045:
1046: void elementIdNotFound(String elementId) {
1047: if (mChildSubsiteIdMapping.containsKey(elementId)) {
1048: throw new ElementIdNotFoundSiteIdExistsException(mSiteId,
1049: elementId);
1050: }
1051:
1052: throw new ElementIdNotFoundInSiteException(mSiteId, elementId);
1053: }
1054:
1055: private void processAutoLinks() {
1056: // process the auto links
1057: HashSet<AutoLinkDeclaration> autolinks = null;
1058: for (String current_elementid : mAutoLinkMapping.keySet()) {
1059: autolinks = mAutoLinkMapping.get(current_elementid);
1060: for (AutoLinkDeclaration autolink_declaration : autolinks) {
1061: autolink_declaration.registerFlowAndDataLinks();
1062: }
1063: }
1064: }
1065:
1066: private void processFlowLinks() {
1067: ElementDeclaration current_elementdeclaration = null;
1068:
1069: // process the flow links
1070: HashSet<FlowLinkDeclaration> flowlinks = null;
1071: for (String current_elementid : mFlowLinkMapping.keySet()) {
1072: current_elementdeclaration = getElementDeclaration(current_elementid);
1073:
1074: flowlinks = mFlowLinkMapping.get(current_elementid);
1075: for (FlowLinkDeclaration flowlink_declaration : flowlinks) {
1076: // add the flowlink to the element info
1077: current_elementdeclaration
1078: .getElementInfo()
1079: .setFlowLink(flowlink_declaration.getFlowLink());
1080: }
1081: }
1082: }
1083:
1084: private void processDataLinks() {
1085: ElementDeclaration current_elementdeclaration = null;
1086: ElementDeclaration target_elementdeclaration = null;
1087:
1088: // process the data links
1089: HashSet<DataLinkDeclaration> datalinks = null;
1090: String datalink_destid = null;
1091: DataLink datalink = null;
1092: for (String current_elementid : mDataLinkMapping.keySet()) {
1093: current_elementdeclaration = getElementDeclaration(current_elementid);
1094:
1095: datalinks = mDataLinkMapping.get(current_elementid);
1096: for (DataLinkDeclaration datalink_declaration : datalinks) {
1097: // resolve target element declaration
1098: if (datalink_declaration.isSnapback()) {
1099: target_elementdeclaration = current_elementdeclaration;
1100: } else {
1101: datalink_destid = datalink_declaration.getDestId();
1102:
1103: // get the element declaration that corresponds to the destination id
1104: target_elementdeclaration = getGlobalElementDeclaration(datalink_destid);
1105:
1106: // if the target element couldn't be found, throw an exception
1107: if (null == target_elementdeclaration) {
1108: elementIdNotFound(datalink_declaration
1109: .getDestId());
1110: }
1111: }
1112:
1113: // handle bean data transfers
1114: if (datalink_declaration.transfersBean()) {
1115: if (!current_elementdeclaration.getElementInfo()
1116: .containsNamedOutbean(
1117: datalink_declaration
1118: .getSrcOutbean())) {
1119: throw new DataLinkUnknownSrcOutbeanException(
1120: mDeclarationName, datalink_declaration
1121: .getSrcOutbean(),
1122: current_elementid, datalink_declaration
1123: .getDestId(),
1124: datalink_declaration.isSnapback());
1125: }
1126: if (!target_elementdeclaration.getElementInfo()
1127: .containsNamedInbean(
1128: datalink_declaration
1129: .getDestInbean())) {
1130: throw new DataLinkUnknownDestInbeanException(
1131: mDeclarationName, datalink_declaration
1132: .getDestInbean(),
1133: current_elementid, datalink_declaration
1134: .getDestId(),
1135: datalink_declaration.isSnapback());
1136: }
1137:
1138: BeanDeclaration srcoutbean = current_elementdeclaration
1139: .getElementInfo().getNamedOutbeanInfo(
1140: datalink_declaration
1141: .getSrcOutbean());
1142: BeanDeclaration destinbean = target_elementdeclaration
1143: .getElementInfo().getNamedInbeanInfo(
1144: datalink_declaration
1145: .getDestInbean());
1146:
1147: Class srcoutbean_class = null;
1148: Class destinbean_class = null;
1149: try {
1150: srcoutbean_class = Class.forName(srcoutbean
1151: .getClassname());
1152: destinbean_class = Class.forName(destinbean
1153: .getClassname());
1154: } catch (ClassNotFoundException e) {
1155: throw new DataLinkBeanErrorException(
1156: mDeclarationName, datalink_declaration
1157: .getSrcOutbean(),
1158: current_elementid, datalink_declaration
1159: .getDestId(),
1160: datalink_declaration.isSnapback(),
1161: datalink_declaration.getDestInbean(), e);
1162: }
1163:
1164: Constrained constrained_destinbean = ConstrainedUtils
1165: .getConstrainedInstance(destinbean_class);
1166:
1167: Set<String> srcoutbean_properties = null;
1168: Set<String> destinbean_properties = null;
1169: try {
1170: srcoutbean_properties = BeanUtils
1171: .getPropertyNames(srcoutbean_class,
1172: null, null, srcoutbean
1173: .getPrefix());
1174: destinbean_properties = BeanUtils
1175: .getPropertyNames(destinbean_class,
1176: null, null, destinbean
1177: .getPrefix());
1178: } catch (BeanUtilsException e) {
1179: throw new DataLinkBeanErrorException(
1180: mDeclarationName, datalink_declaration
1181: .getSrcOutbean(),
1182: current_elementid, datalink_declaration
1183: .getDestId(),
1184: datalink_declaration.isSnapback(),
1185: datalink_declaration.getDestInbean(), e);
1186: }
1187:
1188: for (String srcoutbean_property : srcoutbean_properties) {
1189: datalink = null;
1190:
1191: if (destinbean_properties
1192: .contains(srcoutbean_property)
1193: && ConstrainedUtils
1194: .editConstrainedProperty(
1195: constrained_destinbean,
1196: srcoutbean_property,
1197: srcoutbean.getPrefix())
1198: && current_elementdeclaration
1199: .getElementInfo()
1200: .containsOutputPossibility(
1201: srcoutbean_property)) {
1202: if (datalink_declaration.isSnapback()) {
1203: datalink = new DataLink(
1204: srcoutbean_property, null,
1205: datalink_declaration
1206: .isSnapback(),
1207: srcoutbean_property,
1208: datalink_declaration
1209: .getFlowLink());
1210: current_elementdeclaration
1211: .getElementInfo().addDataLink(
1212: datalink);
1213: } else if (target_elementdeclaration
1214: .getElementInfo()
1215: .containsInputPossibility(
1216: srcoutbean_property)) {
1217: datalink = new DataLink(
1218: srcoutbean_property,
1219: target_elementdeclaration
1220: .getElementInfo(),
1221: datalink_declaration
1222: .isSnapback(),
1223: srcoutbean_property,
1224: datalink_declaration
1225: .getFlowLink());
1226: current_elementdeclaration
1227: .getElementInfo().addDataLink(
1228: datalink);
1229: }
1230: }
1231: }
1232: }
1233: // handle regular values transfer
1234: else {
1235: if (datalink_declaration.isSnapback()) {
1236: datalink = new DataLink(datalink_declaration
1237: .getSrcOutput(), null,
1238: datalink_declaration.isSnapback(),
1239: datalink_declaration.getDestInput(),
1240: datalink_declaration.getFlowLink());
1241: } else {
1242: datalink = new DataLink(datalink_declaration
1243: .getSrcOutput(),
1244: target_elementdeclaration
1245: .getElementInfo(), false,
1246: datalink_declaration.getDestInput(),
1247: datalink_declaration.getFlowLink());
1248: }
1249: current_elementdeclaration.getElementInfo()
1250: .addDataLink(datalink);
1251: }
1252: }
1253: }
1254: }
1255:
1256: private void processFallbackElement() {
1257: if (mFallbackElementId != null) {
1258: ElementInfo fallback_elementinfo = getElementInfo(mFallbackElementId);
1259: if (null == fallback_elementinfo) {
1260: elementIdNotFound(mFallbackElementId);
1261: }
1262: mSite.addFallback(fallback_elementinfo, getUrlPrefix());
1263: }
1264: }
1265:
1266: private void processArrivalElement() {
1267: if (mArrivalElementDeclaration != null) {
1268: // this second pass ensures that the arrival element is linked to and from
1269: // the correct locations
1270: ElementDeclaration target_element_declaration = getElementDeclaration(mArrivalElementId);
1271: mArrivalElementDeclaration.getElementInfo().populateFrom(
1272: target_element_declaration.getElementInfo());
1273: mArrivalElementDeclaration
1274: .setGroup(target_element_declaration.getGroup());
1275:
1276: // ensure & valid arrival id
1277: String arrival_id = mSiteId;
1278:
1279: // only use the site's url prefix if it's the root site or a subsite
1280: // that has its own url prefix
1281: String arrival_url = null;
1282: if (null == mParent
1283: || target_element_declaration.getUrl() != null
1284: || !getUrlPrefix().equals(mParent.getUrlPrefix())) {
1285: arrival_url = getUrlPrefix();
1286: // an arrival should never end with a final slash since that's
1287: // taken care of by the engine gate
1288: if (arrival_url.endsWith("/")) {
1289: arrival_url = StringUtils.stripFromEnd(arrival_url,
1290: "/");
1291: }
1292: }
1293:
1294: // handle arrival redirects
1295: if (mArrivalRedirect) {
1296: mArrivalElementDeclaration.getElementInfo()
1297: .setImplementation(Redirect.class.getName());
1298: HierarchicalProperties properties = mArrivalElementDeclaration
1299: .getElementInfo().getProperties();
1300: properties.put("redirectInputs", true);
1301: properties.put("redirectInputs", true);
1302:
1303: // handle redirects when the target element has no URL
1304: if (null == target_element_declaration.getUrl()) {
1305: properties.put("to", arrival_url + "/");
1306: properties.put("type", "url");
1307: } else {
1308: properties.put("to",
1309: makeAbsoluteElementId(mArrivalElementId));
1310: properties.put("type", "element");
1311: }
1312: }
1313:
1314: // register the arrival element
1315: ElementInfo arrival_elementinfo = mArrivalElementDeclaration
1316: .getElementInfo();
1317: arrival_elementinfo.setId(null);
1318: arrival_elementinfo.setUrl(null);
1319: mSite.addElementInfo(arrival_id, arrival_elementinfo,
1320: arrival_url);
1321:
1322: // ensure that the empty root url isn't mapped twice
1323: if (arrival_url != null && arrival_url.length() > 0) {
1324: // if the arrival redirects, and the target element has got no URL,
1325: // ensure that the URL with a final slash doesn't redirect to itself,
1326: // just map the arrival target element to the URL instead
1327: if (mArrivalRedirect
1328: && null == target_element_declaration.getUrl()) {
1329: mSite.mapElementId(
1330: makeAbsoluteElementId(mArrivalElementId),
1331: arrival_url + "/");
1332: }
1333: // map the URL with a final slash to the same arrival element
1334: else {
1335: mSite.mapElementId(arrival_id, arrival_url + "/");
1336: }
1337: }
1338: }
1339: }
1340:
1341: private void processDepartureElements() {
1342: if (mDepartureIds.size() > 0) {
1343: ElementDeclaration departure_elementdeclaration = null;
1344: for (String departure_id : mDepartureIds) {
1345: departure_elementdeclaration = getElementDeclaration(departure_id);
1346: if (null == departure_elementdeclaration) {
1347: elementIdNotFound(departure_id);
1348: }
1349:
1350: ArrayList<String> departure_vars = new ArrayList<String>(
1351: departure_elementdeclaration.getGroup()
1352: .getGlobalVarsLocal().keySet());
1353:
1354: departure_elementdeclaration.getElementInfo()
1355: .setDepartureVars(departure_vars);
1356: }
1357: }
1358: }
1359:
1360: private void processInheritsStack() {
1361: String parent_id = null;
1362: ElementDeclaration parent_elementdeclaration = null;
1363:
1364: // get the parent elementdeclaration of the elements that inherit from another element
1365: for (ElementDeclaration element_declaration : getElementDeclarations()) {
1366: // obtain the parent elementdeclaration
1367: parent_id = element_declaration.getInherits();
1368: if (parent_id != null) {
1369: parent_elementdeclaration = element_declaration
1370: .getSiteBuilder().getGlobalElementDeclaration(
1371: parent_id);
1372: if (null == parent_elementdeclaration) {
1373: elementIdNotFound(parent_id);
1374: }
1375:
1376: // add it to the parent stack
1377: element_declaration.getParentStack().push(
1378: parent_elementdeclaration);
1379: }
1380: }
1381:
1382: // add the global parents of groups to the elements contained within
1383: if (mGroupDeclarations.size() > 0) {
1384: Stack<ArrayList<GroupDeclaration>> groupdeclarations_stack = null;
1385: GroupDeclaration child_groupdeclaration = null;
1386: ArrayList<GroupDeclaration> child_groupdeclarations = null;
1387: ListIterator<GroupDeclaration> groupdeclarations_it = mGroupDeclarations
1388: .listIterator(mGroupDeclarations.size());
1389: while (groupdeclarations_it.hasPrevious()) {
1390: GroupDeclaration groupdeclaration = groupdeclarations_it
1391: .previous();
1392:
1393: // obtain the parent elementdeclaration
1394: parent_id = groupdeclaration.getInherits();
1395: if (parent_id != null) {
1396: parent_elementdeclaration = groupdeclaration
1397: .getDeclaringSiteBuilder()
1398: .getGlobalElementDeclaration(parent_id);
1399: if (null == parent_elementdeclaration) {
1400: elementIdNotFound(parent_id);
1401: }
1402:
1403: // add it to the stack of all the elements in the group and its groups
1404: groupdeclarations_stack = new Stack<ArrayList<GroupDeclaration>>();
1405: child_groupdeclarations = new ArrayList<GroupDeclaration>();
1406: child_groupdeclarations.add(groupdeclaration);
1407: groupdeclarations_stack
1408: .push(child_groupdeclarations);
1409:
1410: // continue until the stack is empty
1411: while (groupdeclarations_stack.size() > 0) {
1412: // get the top of the stack and process all its groups
1413: child_groupdeclarations = groupdeclarations_stack
1414: .pop();
1415: while (child_groupdeclarations.size() > 0) {
1416: // add the global parent to all the elements within the group
1417: child_groupdeclaration = child_groupdeclarations
1418: .remove(0);
1419: for (ElementDeclaration child_elementdeclaration : child_groupdeclaration
1420: .getElementDeclarations()) {
1421: child_elementdeclaration
1422: .getParentStack()
1423: .push(parent_elementdeclaration);
1424: }
1425:
1426: // if the group contain other groups, add the collection to the stack
1427: if (child_groupdeclaration
1428: .getChildGroupDeclarations().size() > 0) {
1429: groupdeclarations_stack
1430: .push(new ArrayList<GroupDeclaration>(
1431: child_groupdeclaration
1432: .getChildGroupDeclarations()));
1433: }
1434: }
1435: }
1436: }
1437: }
1438: }
1439: }
1440:
1441: private void processPreStack() {
1442: String pre_id = null;
1443: ElementDeclaration pre_elementdeclaration = null;
1444:
1445: // get the pre elementdeclaration of the elements that inherit from another element
1446: for (ElementDeclaration element_declaration : getElementDeclarations()) {
1447: // obtain the pre elementdeclaration
1448: pre_id = element_declaration.getPre();
1449: if (pre_id != null) {
1450: pre_elementdeclaration = element_declaration
1451: .getSiteBuilder().getGlobalElementDeclaration(
1452: pre_id);
1453: if (null == pre_elementdeclaration) {
1454: elementIdNotFound(pre_id);
1455: }
1456:
1457: // add it to the pre stack
1458: element_declaration.getPreStack().push(
1459: pre_elementdeclaration);
1460: }
1461: }
1462:
1463: // add the global pres of groups to the elements contained within
1464: if (mGroupDeclarations.size() > 0) {
1465: Stack<ArrayList<GroupDeclaration>> groupdeclarations_stack = null;
1466: GroupDeclaration child_groupdeclaration = null;
1467: ArrayList<GroupDeclaration> child_groupdeclarations = null;
1468: ListIterator<GroupDeclaration> groupdeclarations_it = mGroupDeclarations
1469: .listIterator(mGroupDeclarations.size());
1470: while (groupdeclarations_it.hasPrevious()) {
1471: GroupDeclaration groupdeclaration = groupdeclarations_it
1472: .previous();
1473:
1474: // obtain the pre elementdeclaration
1475: pre_id = groupdeclaration.getPre();
1476: if (pre_id != null) {
1477: pre_elementdeclaration = groupdeclaration
1478: .getDeclaringSiteBuilder()
1479: .getGlobalElementDeclaration(pre_id);
1480: if (null == pre_elementdeclaration) {
1481: elementIdNotFound(pre_id);
1482: }
1483:
1484: // add it to the stack of all the elements in the group and its groups
1485: groupdeclarations_stack = new Stack<ArrayList<GroupDeclaration>>();
1486: child_groupdeclarations = new ArrayList<GroupDeclaration>();
1487: child_groupdeclarations.add(groupdeclaration);
1488: groupdeclarations_stack
1489: .push(child_groupdeclarations);
1490:
1491: // continue until the stack is empty
1492: while (groupdeclarations_stack.size() > 0) {
1493: // get the top of the stack and process all its groups
1494: child_groupdeclarations = groupdeclarations_stack
1495: .pop();
1496: while (child_groupdeclarations.size() > 0) {
1497: // add the global pre to all the elements within the group
1498: child_groupdeclaration = child_groupdeclarations
1499: .remove(0);
1500: for (ElementDeclaration child_elementdeclaration : child_groupdeclaration
1501: .getElementDeclarations()) {
1502: child_elementdeclaration.getPreStack()
1503: .push(pre_elementdeclaration);
1504: }
1505:
1506: // if the group contain other groups, add the collection to the stack
1507: if (child_groupdeclaration
1508: .getChildGroupDeclarations().size() > 0) {
1509: groupdeclarations_stack
1510: .push(new ArrayList<GroupDeclaration>(
1511: child_groupdeclaration
1512: .getChildGroupDeclarations()));
1513: }
1514: }
1515: }
1516: }
1517: }
1518: }
1519: }
1520:
1521: private void createInheritanceStacks() {
1522: // create the inheritance stack of the elements of subsites first
1523: for (SubsiteDeclaration subsitedeclaration : mChildSubsiteDeclarations) {
1524: subsitedeclaration.getSiteBuilder()
1525: .createInheritanceStacks();
1526: }
1527:
1528: // create the inheritance stack of all the elements in this subsite
1529: // construct each element's inheritance stack
1530: Stack<ElementInfo> inheritance_stack = null;
1531: String parent_id = null;
1532:
1533: for (ElementDeclaration current_elementdeclaration : getElementDeclarations()) {
1534: if (current_elementdeclaration.getParentStack().size() > 0) {
1535: inheritance_stack = new Stack<ElementInfo>();
1536:
1537: // the element itself should be at the bottom of inheritance stack
1538: inheritance_stack.push(current_elementdeclaration
1539: .getElementInfo());
1540:
1541: // iterate over all the elements in the parent stack
1542: for (ElementDeclaration parent_elementdeclaration : current_elementdeclaration
1543: .getParentStack()) {
1544: // lookup and resolve the parent hierarchy of an element in the parent stack
1545: while (parent_elementdeclaration != null) {
1546: inheritance_stack
1547: .push(parent_elementdeclaration
1548: .getElementInfo());
1549: parent_id = parent_elementdeclaration
1550: .getInherits();
1551: if (null == parent_id) {
1552: parent_elementdeclaration = null;
1553: } else {
1554: parent_elementdeclaration = parent_elementdeclaration
1555: .getSiteBuilder()
1556: .getGlobalElementDeclaration(
1557: parent_id);
1558: }
1559: }
1560: }
1561:
1562: // store the inheritance stack
1563: current_elementdeclaration.getElementInfo()
1564: .setInheritanceStack(inheritance_stack);
1565: }
1566: }
1567: }
1568:
1569: private void createPrecedenceStacks() {
1570: // create the precedence stack of the elements of subsites first
1571: for (SubsiteDeclaration subsitedeclaration : mChildSubsiteDeclarations) {
1572: subsitedeclaration.getSiteBuilder()
1573: .createPrecedenceStacks();
1574: }
1575:
1576: // create the precedence stack of all the elements in this subsite
1577: // construct each element's precedence stack
1578: Stack<ElementInfo> precedence_stack = null;
1579:
1580: for (ElementDeclaration current_elementdeclaration : getElementDeclarations()) {
1581: if (current_elementdeclaration.getPreStack().size() > 0) {
1582: precedence_stack = new Stack<ElementInfo>();
1583:
1584: // the element itself should be at the bottom of precedence stack
1585: precedence_stack.push(current_elementdeclaration
1586: .getElementInfo());
1587:
1588: // iterate over all the elements in the pre stack and resolve them to element infos
1589: for (ElementDeclaration pre_elementdeclaration : current_elementdeclaration
1590: .getPreStack()) {
1591: precedence_stack.push(pre_elementdeclaration
1592: .getElementInfo());
1593: }
1594:
1595: // store the precedence stack
1596: current_elementdeclaration.getElementInfo()
1597: .setPrecedenceStack(precedence_stack);
1598: }
1599: }
1600: }
1601:
1602: private void setupData() {
1603: setupElements();
1604: setupSubsites();
1605: setupArrivalElement();
1606: }
1607:
1608: private void processData() {
1609: processSubsites();
1610: processGlobalExits();
1611: processAutoLinks();
1612: processFlowLinks();
1613: processDataLinks();
1614: processFallbackElement();
1615: processArrivalElement();
1616: processDepartureElements();
1617: processInheritsStack();
1618: processPreStack();
1619:
1620: // clean the temporary data
1621: mArrivalElementId = null;
1622: mDepartureIds = null;
1623: mDataLinkMapping = null;
1624: mFlowLinkMapping = null;
1625: mAutoLinkMapping = null;
1626: }
1627:
1628: private String getUrlPrefix() {
1629: if (mUrlPrefix != null) {
1630: return mUrlPrefix;
1631: }
1632:
1633: if (null == mParent) {
1634: mUrlPrefix = "/";
1635: } else {
1636: String url_prefix = getParent().getUrlPrefix();
1637: if (mSubsiteDeclaration.getUrlPrefix() != null) {
1638: // prevent double slashes
1639: String subsite_url_prefix = mSubsiteDeclaration
1640: .getUrlPrefix();
1641: if (url_prefix.endsWith("/")
1642: && subsite_url_prefix.startsWith("/")) {
1643: url_prefix = StringUtils.stripFromEnd(url_prefix,
1644: "/");
1645: subsite_url_prefix = StringUtils.stripFromFront(
1646: subsite_url_prefix, "/");
1647: StringBuilder buffer = new StringBuilder(url_prefix);
1648: buffer.append("/");
1649: buffer.append(subsite_url_prefix);
1650: url_prefix = buffer.toString();
1651: } else if (url_prefix.endsWith("/")
1652: || subsite_url_prefix.startsWith("/")) {
1653: url_prefix = url_prefix + subsite_url_prefix;
1654: } else {
1655: StringBuilder buffer = new StringBuilder(url_prefix);
1656: buffer.append("/");
1657: buffer.append(subsite_url_prefix);
1658: url_prefix = buffer.toString();
1659: }
1660: }
1661:
1662: mUrlPrefix = url_prefix;
1663: }
1664:
1665: return mUrlPrefix;
1666: }
1667:
1668: String getDeclarationName() {
1669: return mDeclarationName;
1670: }
1671:
1672: void addDataLink(String srcId, DataLinkDeclaration dataLink,
1673: boolean overrideExisting) {
1674: HashSet<DataLinkDeclaration> datalinks = mDataLinkMapping
1675: .get(srcId);
1676:
1677: if (null == datalinks) {
1678: datalinks = new HashSet<DataLinkDeclaration>();
1679: mDataLinkMapping.put(srcId, datalinks);
1680: }
1681:
1682: if (overrideExisting || !datalinks.contains(dataLink)) {
1683: datalinks.add(dataLink);
1684: }
1685: }
1686:
1687: void addFlowLink(String srcId, FlowLinkDeclaration flowLink) {
1688: HashSet<FlowLinkDeclaration> flowlinks = mFlowLinkMapping
1689: .get(srcId);
1690:
1691: if (null == flowlinks) {
1692: flowlinks = new HashSet<FlowLinkDeclaration>();
1693: mFlowLinkMapping.put(srcId, flowlinks);
1694: }
1695:
1696: flowlinks.add(flowLink);
1697: }
1698:
1699: void addAutoLink(String srcId, AutoLinkDeclaration autoLink) {
1700: HashSet<AutoLinkDeclaration> autolinks = mAutoLinkMapping
1701: .get(srcId);
1702:
1703: if (null == autolinks) {
1704: autolinks = new HashSet<AutoLinkDeclaration>();
1705: mAutoLinkMapping.put(srcId, autolinks);
1706: }
1707:
1708: autolinks.add(autoLink);
1709: }
1710:
1711: String ensureLocalElementId(String id) throws EngineException {
1712: if (id != null) {
1713: if (id.indexOf(".") != -1 || id.indexOf("^") != -1) {
1714: throw new LocalElementIdRequiredException(id);
1715: }
1716: }
1717:
1718: return id;
1719: }
1720:
1721: String makeAbsoluteElementId(String id) {
1722: if (null == id) {
1723: return null;
1724: }
1725:
1726: if (!id.startsWith(".")) {
1727: id = getId() + id;
1728: }
1729:
1730: return id;
1731: }
1732:
1733: static String generateId(String declarationName) {
1734: if (null == declarationName) {
1735: return null;
1736: }
1737:
1738: String id = FileUtils.getBaseName(declarationName);
1739: if (null == id) {
1740: id = declarationName;
1741: }
1742: int index = id.lastIndexOf("/");
1743: if (-1 == index) {
1744: index = id.lastIndexOf(":");
1745: }
1746: if (index != -1) {
1747: if (index == id.length() - 1) {
1748: id = null;
1749: } else {
1750: id = id.substring(index + 1);
1751: }
1752: }
1753:
1754: return id;
1755: }
1756:
1757: public SiteBuilder addResourceModificationTime(
1758: UrlResource resource, long modificationTime) {
1759: if (RifeConfig.Engine.getSiteAutoReload()) {
1760: mSite.addResourceModificationTime(resource,
1761: modificationTime);
1762: }
1763:
1764: return this;
1765: }
1766: }
|