/* * Copyright 2007 (C) Tom Parker <thpr@users.sourceforge.net> * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package pcgen.rules.context; import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import pcgen.base.formula.base.LegalScope; import pcgen.base.formula.base.ScopeInstance; import pcgen.base.formula.inst.SimpleScopeInstance; import pcgen.base.text.ParsingSeparator; import pcgen.cdom.base.CDOMObject; import pcgen.cdom.base.CDOMReference; import pcgen.cdom.base.GroupDefinition; import pcgen.cdom.base.Loadable; import pcgen.cdom.base.PrimitiveCollection; import pcgen.cdom.enumeration.DataSetID; import pcgen.cdom.facet.DataSetInitializationFacet; import pcgen.cdom.facet.FacetInitialization; import pcgen.cdom.facet.FacetLibrary; import pcgen.cdom.inst.ObjectCache; import pcgen.cdom.reference.ReferenceManufacturer; import pcgen.cdom.reference.SelectionCreator; import pcgen.core.Campaign; import pcgen.core.prereq.Prerequisite; import pcgen.persistence.PersistenceLayerException; import pcgen.persistence.lst.CampaignSourceEntry; import pcgen.persistence.lst.output.prereq.PrerequisiteWriter; import pcgen.rules.persistence.ChoiceSetLoadUtilities; import pcgen.rules.persistence.TokenLibrary; import pcgen.rules.persistence.TokenSupport; import pcgen.rules.persistence.token.DeferredToken; import pcgen.rules.persistence.token.ParseResult; import pcgen.rules.persistence.token.PostDeferredToken; import pcgen.rules.persistence.token.PostValidationToken; import pcgen.util.Logging; abstract class LoadContextInst implements LoadContext { private static final PrerequisiteWriter PREREQ_WRITER = new PrerequisiteWriter(); private final DataSetID datasetID = DataSetID.getID(); private final AbstractListContext list; private final AbstractObjectContext obj; private final AbstractReferenceContext ref; private final VariableContext var; private final List<Campaign> campaignList = new ArrayList<>(); private int writeMessageCount = 0; private final TokenSupport support = new TokenSupport(); private final List<Object> dontForget = new ArrayList<>(); //Per file private URI sourceURI; //Per file private CDOMObject stateful; private ScopeInstance scopeInst = null; static { FacetInitialization.initialize(); } public LoadContextInst(AbstractReferenceContext rc, AbstractListContext lc, AbstractObjectContext oc) { if (rc == null) { throw new IllegalArgumentException("ReferenceContext cannot be null"); } if (lc == null) { throw new IllegalArgumentException("ListContext cannot be null"); } if (oc == null) { throw new IllegalArgumentException("ObjectContext cannot be null"); } ref = rc; list = lc; obj = oc; var = new VariableContext(); } @Override public void addWriteMessage(String string) { Logging.errorPrint("!!" + string); /* * TODO Need to find a better solution for what happens during write... */ writeMessageCount++; } @Override public int getWriteMessageCount() { return writeMessageCount; } /** * Sets the extract URI. This is a shortcut for setting the URI on both the * graph and obj members. * * @param extractURI */ @Override public void setExtractURI(URI extractURI) { getObjectContext().setExtractURI(extractURI); getReferenceContext().setExtractURI(extractURI); getListContext().setExtractURI(extractURI); } /** * Sets the source URI. This is a shortcut for setting the URI on both the * graph and obj members. * * @param sourceURI */ @Override public void setSourceURI(URI sourceURI) { this.sourceURI = sourceURI; getObjectContext().setSourceURI(sourceURI); getReferenceContext().setSourceURI(sourceURI); getListContext().setSourceURI(sourceURI); clearStatefulInformation(); Logging.debugPrint("Starting Load of " + sourceURI); } @Override public URI getSourceURI() { return sourceURI; } /* * Get the type of context we're running in (either Editor or Runtime) */ public abstract String getContextType(); @Override public AbstractObjectContext getObjectContext() { return obj; } @Override public AbstractListContext getListContext() { return list; } @Override public VariableContext getVariableContext() { return var; } @Override public void commit() { getListContext().commit(); getObjectContext().commit(); } @Override public void rollback() { getListContext().rollback(); getObjectContext().rollback(); } @Override public void resolveDeferredTokens() { for (DeferredToken<? extends Loadable> token : support. getDeferredTokens()) { processRes(token); } commit(); } private <T extends Loadable> void processRes(DeferredToken<T> token) { Class<T> cl = token.getDeferredTokenClass(); Collection<? extends ReferenceManufacturer<?>> mfgs = getReferenceContext() .getAllManufacturers(); for (ReferenceManufacturer<?> rm : mfgs) { if (cl.isAssignableFrom(rm.getReferenceClass())) { @SuppressWarnings("unchecked") ReferenceManufacturer<? extends T> trm = (ReferenceManufacturer<? extends T>) rm; for (T po : trm.getAllObjects()) { token.process(this, po); } for (T po : trm.getDerivativeObjects()) { token.process(this, po); } } } } @Override public void resolvePostDeferredTokens() { Collection<? extends ReferenceManufacturer<?>> mfgs = getReferenceContext() .getAllManufacturers(); for (PostDeferredToken<? extends Loadable> token : TokenLibrary.getPostDeferredTokens()) { processPostRes(token, mfgs); } } private <T extends Loadable> void processPostRes(PostDeferredToken<T> token, Collection<? extends ReferenceManufacturer<?>> mfgs) { Class<T> cl = token.getDeferredTokenClass(); for (ReferenceManufacturer<?> rm : mfgs) { if (cl.isAssignableFrom(rm.getReferenceClass())) { @SuppressWarnings("unchecked") ReferenceManufacturer<? extends T> trm = (ReferenceManufacturer<? extends T>) rm; for (T po : trm.getAllObjects()) { this.setSourceURI(po.getSourceURI()); token.process(this, po); } } } } @Override public void resolvePostValidationTokens() { Collection<? extends ReferenceManufacturer> mfgs = getReferenceContext() .getAllManufacturers(); for (PostValidationToken<? extends Loadable> token : TokenLibrary.getPostValidationTokens()) { processPostVal(token, mfgs); } } private <T extends Loadable> void processPostVal(PostValidationToken<T> token, Collection<? extends ReferenceManufacturer> mfgs) { Class<T> cl = token.getValidationTokenClass(); for (ReferenceManufacturer<? extends T> rm : mfgs) { if (cl.isAssignableFrom(rm.getReferenceClass())) { setSourceURI(null); token.process(this, rm.getAllObjects()); } } } @Override public <T extends CDOMObject> PrimitiveCollection<T> getChoiceSet( SelectionCreator<T> sc, String value) { try { return ChoiceSetLoadUtilities.getChoiceSet(this, sc, value); } catch (ParsingSeparator.GroupingMismatchException e) { Logging.errorPrint("Group Mismatch in getting ChoiceSet: " + e.getMessage()); return null; } } @Override public <T extends CDOMObject> PrimitiveCollection<T> getPrimitiveChoiceFilter( SelectionCreator<T> sc, String key) { return ChoiceSetLoadUtilities.getPrimitive(this, sc, key); } @Override public <T> ParseResult processSubToken(T cdo, String tokenName, String key, String value) { return support.processSubToken(this, cdo, tokenName, key, value); } @Override public <T extends Loadable> boolean processToken(T derivative, String typeStr, String argument) throws PersistenceLayerException { return support.processToken(this, derivative, typeStr, argument); } @Override public <T extends Loadable> void unconditionallyProcess(T cdo, String key, String value) { try { if (processToken(cdo, key, value)) { commit(); } else { rollback(); Logging.replayParsedMessages(); } Logging.clearParseMessages(); } catch (PersistenceLayerException e) { Logging.errorPrint("Error in token parse: " + e.getLocalizedMessage()); } } /** * Produce the LST code for any occurrences of subtokens of the parent token. * * @param <T> The type of object to be processed, generally a CDOMObject. * @param cdo The object to be partially unparsed * @param tokenName The name of the parent token * @return An array of LST code 'fields' all of which are subtokens of the parent token. */ @Override public <T> String[] unparseSubtoken(T cdo, String tokenName) { return support.unparseSubtoken(this, cdo, tokenName); } @Override public <T> Collection<String> unparse(T cdo) { return support.unparse(this, cdo); } @Override public <T extends CDOMObject> T cloneConstructedCDOMObject(T cdo, String newName) { T newObj = getObjectContext().cloneConstructedCDOMObject(cdo, newName); getReferenceContext().importObject(newObj); return newObj; } /** * Create a copy of a CDOMObject duplicating any references to the old * object. (e.g. Spell, Domain etc) * * Package protected rather than private for testing only * * @param cdo The original object being copied. * @param newName The name that should be given to the new object. * @return The newly created CDOMObject. */ @SuppressWarnings("unchecked") <T extends CDOMObject> T cloneInMasterLists(T cdo, String newName) { T newObj; try { newObj = (T) cdo.clone(); newObj.setName(newName); getListContext().cloneInMasterLists(cdo, newObj); } catch (CloneNotSupportedException e) { Logging.errorPrint("Failed to clone " + cdo, e); return null; } return newObj; } @Override public String getPrerequisiteString(Collection<Prerequisite> prereqs) { try { return PREREQ_WRITER.getPrerequisiteString(prereqs); } catch (PersistenceLayerException e) { addWriteMessage("Error writing Prerequisite: " + e); return null; } } @Override public CampaignSourceEntry getCampaignSourceEntry(Campaign source, String value) { return CampaignSourceEntry.getNewCSE(source, sourceURI, value); } @Override public void clearStatefulInformation() { stateful = null; } @Override public boolean addStatefulToken(String s) throws PersistenceLayerException { int colonLoc = s.indexOf(':'); if (colonLoc == -1) { Logging.errorPrint("Found invalid stateful token: " + s); return false; } if (stateful == null) { stateful = new ObjectCache(); } return processToken(stateful, s.substring(0, colonLoc).intern(), s.substring(colonLoc + 1).intern()); } @Override public void addStatefulInformation(CDOMObject target) { if (stateful != null) { target.overlayCDOMObject(stateful); } } @Override public void setLoaded(List<Campaign> campaigns) { campaignList.clear(); campaignList.addAll(campaigns); } @Override public abstract boolean consolidate(); @Override public DataSetID getDataSetID() { return datasetID; } @Override public void loadCampaignFacets() { FacetLibrary.getFacet(DataSetInitializationFacet.class).initialize(this); } @Override public void forgetMeNot(CDOMReference<?> cdr) { dontForget.add(cdr); } @Override public AbstractReferenceContext getReferenceContext() { return ref; } @Override public List<Campaign> getLoadedCampaigns() { return Collections.unmodifiableList(campaignList); } @Override public ReferenceManufacturer<? extends Loadable> getManufacturer( String firstToken) { return ReferenceContextUtilities.getManufacturer(getReferenceContext(), firstToken); } @Override public <T extends CDOMObject> T performCopy(T object, String copyName) { T copy = ref.performCopy(object, copyName); list.cloneInMasterLists(object, copy); return copy; } @Override public void loadLocalToken(Object token) { support.loadLocalToken(token); } @Override public <T> GroupDefinition<T> getGroup(Class<T> cl, String s) { return support.getGroup(cl, s); } @Override public ScopeInstance getActiveScope() { if (scopeInst == null) { LegalScope legalScope = var.getScope("Global"); scopeInst = new SimpleScopeInstance(null, legalScope, "Global"); } return scopeInst; } @Override public LoadContext dropIntoContext(String scope) { LegalScope legalScope = var.getScope(scope); if (legalScope == null) { throw new IllegalArgumentException("LegalVariableScope " + scope + " does not exist"); } return dropIntoContext(legalScope); } private LoadContext dropIntoContext(LegalScope lvs) { LegalScope parent = lvs.getParentScope(); if (parent == null) { //is Global return this; } LoadContext parentLC = dropIntoContext(parent); SimpleScopeInstance localInst = new SimpleScopeInstance(parentLC.getActiveScope(), lvs, "Context (during Load)"); return new DerivedLoadContext(parentLC, localInst); } private class DerivedLoadContext implements LoadContext { private final LoadContext parent; private final ScopeInstance scopeInst; public DerivedLoadContext(LoadContext parent, ScopeInstance lvs) { this.scopeInst = lvs; this.parent = parent; } @Override public void setExtractURI(URI extractURI) { parent.setExtractURI(extractURI); } @Override public void setSourceURI(URI sourceURI) { parent.setSourceURI(sourceURI); } @Override public URI getSourceURI() { return parent.getSourceURI(); } @Override public DataSetID getDataSetID() { return parent.getDataSetID(); } @Override public AbstractReferenceContext getReferenceContext() { return parent.getReferenceContext(); } @Override public AbstractObjectContext getObjectContext() { return parent.getObjectContext(); } @Override public AbstractListContext getListContext() { return parent.getListContext(); } @Override public boolean consolidate() { return parent.consolidate(); } @Override public VariableContext getVariableContext() { return parent.getVariableContext(); } @Override public void commit() { parent.commit(); } @Override public void rollback() { parent.rollback(); } @Override public void resolveDeferredTokens() { parent.resolveDeferredTokens(); } @Override public void resolvePostDeferredTokens() { parent.resolvePostDeferredTokens(); } @Override public <T extends CDOMObject> PrimitiveCollection<T> getChoiceSet( SelectionCreator<T> sc, String value) { return parent.getChoiceSet(sc, value); } @Override public <T extends CDOMObject> PrimitiveCollection<T> getPrimitiveChoiceFilter( SelectionCreator<T> sc, String key) { return parent.getPrimitiveChoiceFilter(sc, key); } @Override public String getPrerequisiteString(Collection<Prerequisite> prereqs) { return parent.getPrerequisiteString(prereqs); } @Override public ReferenceManufacturer<? extends Loadable> getManufacturer( String firstToken) { return parent.getManufacturer(firstToken); } @Override public void forgetMeNot(CDOMReference<?> cdr) { parent.forgetMeNot(cdr); } @Override public <T extends CDOMObject> T cloneConstructedCDOMObject(T cdo, String newName) { return parent.cloneConstructedCDOMObject(cdo, newName); } @Override public CampaignSourceEntry getCampaignSourceEntry(Campaign source, String value) { return parent.getCampaignSourceEntry(source, value); } @Override public void clearStatefulInformation() { parent.clearStatefulInformation(); } @Override public boolean addStatefulToken(String s) throws PersistenceLayerException { return parent.addStatefulToken(s); } @Override public void addStatefulInformation(CDOMObject target) { parent.addStatefulInformation(target); } @Override public void setLoaded(List<Campaign> campaigns) { parent.setLoaded(campaigns); } @Override public List<Campaign> getLoadedCampaigns() { return parent.getLoadedCampaigns(); } @Override public void loadCampaignFacets() { parent.loadCampaignFacets(); } @Override public <T extends CDOMObject> T performCopy(T object, String copyName) { return parent.performCopy(object, copyName); } @Override public <T> ParseResult processSubToken(T cdo, String tokenName, String key, String value) { return support.processSubToken(this, cdo, tokenName, key, value); } @Override public <T extends Loadable> boolean processToken(T derivative, String typeStr, String argument) throws PersistenceLayerException { return support.processToken(this, derivative, typeStr, argument); } @Override public <T extends Loadable> void unconditionallyProcess(T cdo, String key, String value) { parent.unconditionallyProcess(cdo, key, value); } @Override public <T> String[] unparseSubtoken(T cdo, String tokenName) { return support.unparseSubtoken(this, cdo, tokenName); } @Override public <T> Collection<String> unparse(T cdo) { return support.unparse(this, cdo); } @Override public void addWriteMessage(String string) { parent.addWriteMessage(string); } @Override public int getWriteMessageCount() { return parent.getWriteMessageCount(); } @Override public ScopeInstance getActiveScope() { return scopeInst; } @Override public LoadContext dropIntoContext(String scope) { LegalScope toScope = var.getScope(scope); if (toScope == null) { throw new IllegalArgumentException("LegalVariableScope " + scope + " does not exist"); } LegalScope currentScope = scopeInst.getLegalScope(); if (currentScope.equals(toScope)) { return this; } else if (currentScope.getParentScope().equals(toScope)) { //Jump up from here return parent; } else if (toScope.getParentScope().equals(currentScope)) { //Direct drop from this SimpleScopeInstance localInst = new SimpleScopeInstance(scopeInst, toScope, "Context (during Load)"); return new DerivedLoadContext(this, localInst); } //Random jump to somewhere else... return LoadContextInst.this.dropIntoContext(toScope); } @Override public void loadLocalToken(Object token) { parent.loadLocalToken(token); } @Override public <T> GroupDefinition<T> getGroup(Class<T> cl, String s) { return parent.getGroup(cl, s); } @Override public void resolvePostValidationTokens() { parent.resolvePostValidationTokens(); } } }