001: /*
002: * Created on Nov 12, 2005
003: */
004: package uk.org.ponder.rsf.state;
005:
006: import uk.org.ponder.beanutil.BeanLocator;
007: import uk.org.ponder.beanutil.BeanModelAlterer;
008: import uk.org.ponder.beanutil.BeanPredicateModel;
009: import uk.org.ponder.beanutil.ELReference;
010: import uk.org.ponder.mapping.BeanInvalidationBracketer;
011: import uk.org.ponder.mapping.BeanInvalidationModel;
012: import uk.org.ponder.mapping.ConverterConverter;
013: import uk.org.ponder.mapping.DAREnvironment;
014: import uk.org.ponder.mapping.DARList;
015: import uk.org.ponder.mapping.DARReshaper;
016: import uk.org.ponder.mapping.DataAlterationRequest;
017: import uk.org.ponder.mapping.DataConverterRegistry;
018: import uk.org.ponder.mapping.ListBeanInvalidationModel;
019: import uk.org.ponder.mapping.ShellInfo;
020: import uk.org.ponder.messageutil.TargettedMessage;
021: import uk.org.ponder.messageutil.TargettedMessageList;
022: import uk.org.ponder.rsf.request.ActionTarget;
023: import uk.org.ponder.rsf.request.RequestSubmittedValueCache;
024: import uk.org.ponder.rsf.request.SubmittedValueEntry;
025: import uk.org.ponder.rsf.state.guards.BeanGuardProcessor;
026: import uk.org.ponder.rsf.uitype.UIType;
027: import uk.org.ponder.rsf.uitype.UITypes;
028: import uk.org.ponder.util.Logger;
029: import uk.org.ponder.util.RunnableInvoker;
030: import uk.org.ponder.util.UniversalRuntimeException;
031:
032: public class RSVCApplier {
033: private VersionCheckPolicy versioncheckpolicy;
034: private BeanModelAlterer darapplier;
035: private BeanInvalidationModel bim;
036: private BeanGuardProcessor beanGuardProcessor;
037: private boolean ignoreFossilizedValues = true;
038: private TargettedMessageList targettedMessageList;
039: private BeanLocator rbl;
040: private DataConverterRegistry dataConverterRegistry;
041: private BeanPredicateModel addressibleBeanModel;
042:
043: public void setAddressibleBeanModel(
044: BeanPredicateModel addressibleBeanModel) {
045: this .addressibleBeanModel = addressibleBeanModel;
046: }
047:
048: public void setIgnoreFossilizedValues(boolean ignoreFossilizedValues) {
049: this .ignoreFossilizedValues = ignoreFossilizedValues;
050: }
051:
052: public void setBeanModelAlterer(BeanModelAlterer darapplier) {
053: this .darapplier = darapplier;
054: }
055:
056: public void setVersionCheckPolicy(
057: VersionCheckPolicy versioncheckpolicy) {
058: this .versioncheckpolicy = versioncheckpolicy;
059: }
060:
061: public void setBeanInvalidationModel(BeanInvalidationModel bim) {
062: this .bim = bim;
063: }
064:
065: public void setBeanGuardProcessor(
066: BeanGuardProcessor beanGuardProcessor) {
067: this .beanGuardProcessor = beanGuardProcessor;
068: }
069:
070: public void setTargettedMessageList(
071: TargettedMessageList targettedMessageList) {
072: this .targettedMessageList = targettedMessageList;
073: }
074:
075: public void setRootBeanLocator(BeanLocator rbl) {
076: this .rbl = rbl;
077: }
078:
079: public void setDataConverterRegistry(
080: DataConverterRegistry dataConverterRegistry) {
081: this .dataConverterRegistry = dataConverterRegistry;
082: }
083:
084: public void applyAlterations(DARList toapply) {
085: try {
086: BeanInvalidationBracketer bib = getBracketer();
087: darapplier
088: .applyAlterations(rbl, toapply,
089: new DAREnvironment(targettedMessageList,
090: bib, addressibleBeanModel,
091: dataConverterRegistry));
092: } finally {
093: beanGuardProcessor.processPostGuards(bim,
094: targettedMessageList, rbl);
095: }
096: }
097:
098: /**
099: * Apply values from this RSVC to the model, and in addition process any
100: * validations specified by BeanGuards.
101: */
102: public void applyValues(RequestSubmittedValueCache rsvc) {
103: // TODO: There is scope for a lot of policy here - mainly version checking.
104: // Define a VersionCheckPolicy that will compare oldvalue to the model
105: // value.
106: DARList toapply = new DARList();
107:
108: for (int i = 0; i < rsvc.getEntries(); ++i) {
109: SubmittedValueEntry sve = rsvc.entryAt(i);
110: boolean unchangedValue = false;
111: // check against "old" values
112: if (sve.componentid != null && !ignoreFossilizedValues
113: && !sve.mustapply) {
114: if (sve.oldvalue != null && sve.valuebinding != null) {
115: versioncheckpolicy.checkOldVersion(sve); // will blow on error
116:
117: UIType type = UITypes.forObject(sve.oldvalue);
118: try {
119: // TODO: why did we need to hack the value flat like this - should
120: // have been taken care of by FixupNewValue in PostDecoder
121: Object flattened = darapplier
122: .getFlattenedValue("", sve.newvalue,
123: sve.oldvalue.getClass(), null);
124: // cull the change from touching the model.
125: if (type
126: .valueUnchanged(sve.oldvalue, flattened))
127: unchangedValue = true;
128: } catch (Exception e) {
129: Logger.log.warn("Error flattening value"
130: + sve.newvalue + " into "
131: + sve.oldvalue.getClass(), e);
132: }
133: }
134: }
135: DataAlterationRequest dar = null;
136: // NB unchanged CANNOT be EL or deletion SVE.
137: Object newvalue = unchangedValue ? DataAlterationRequest.INAPPLICABLE_VALUE
138: : sve.newvalue;
139: if (sve.isEL) {
140: newvalue = new ELReference((String) sve.newvalue);
141: }
142: if (sve.isdeletion) {
143: dar = new DataAlterationRequest(sve.valuebinding,
144: newvalue, DataAlterationRequest.DELETE);
145: } else {
146: dar = new DataAlterationRequest(sve.valuebinding,
147: newvalue);
148: }
149: Object reshapero = null;
150: if (sve.reshaperbinding != null) {
151: reshapero = darapplier.getBeanValue(
152: sve.reshaperbinding, rbl, addressibleBeanModel);
153: } else {
154: try {
155: ShellInfo shellinfo = darapplier.fetchShells(
156: sve.valuebinding, rbl, false);
157: reshapero = dataConverterRegistry
158: .fetchConverter(shellinfo);
159: } catch (Exception e) {
160: throw UniversalRuntimeException.accumulate(e,
161: "Error traversing binding path "
162: + sve.valuebinding);
163: }
164: }
165: if (reshapero != null) {
166: DARReshaper reshaper = ConverterConverter
167: .toReshaper(reshapero);
168: try {
169: dar = reshaper.reshapeDAR(dar);
170: } catch (Exception e) {
171: Logger.log.info("Error reshaping value", e);
172: // errors initially accumulated referring to paths
173: targettedMessageList
174: .addMessage(new TargettedMessage(e
175: .getMessage(), e, dar.path));
176: }
177: }
178: toapply.add(dar);
179:
180: }
181: applyAlterations(toapply);
182: }
183:
184: public BeanInvalidationBracketer getBracketer() {
185: return new BeanInvalidationBracketer() {
186: public void invalidate(String path, Runnable toinvoke) {
187: bim.invalidate(path);
188: ListBeanInvalidationModel singlebim = new ListBeanInvalidationModel();
189: singlebim.invalidate(path);
190: RunnableInvoker invoker = beanGuardProcessor
191: .getGuardProcessor(singlebim,
192: targettedMessageList, rbl);
193: invoker.invokeRunnable(toinvoke);
194: }
195: };
196: }
197:
198: public Object invokeAction(String actionbinding, String knownvalue) {
199: if (!addressibleBeanModel.isMatch(actionbinding)) {
200: throw UniversalRuntimeException
201: .accumulate(
202: new SecurityException(),
203: "Action binding "
204: + actionbinding
205: + " is not permissible - make sure to mark this path as request addressible - http://www2.caret.cam.ac.uk/rsfwiki/Wiki.jsp?page=RequestWriteableBean");
206: }
207: ShellInfo shells = darapplier.fetchShells(actionbinding, rbl,
208: true);
209: int lastshell = shells.shells.length;
210: for (int i = 0; i < lastshell; ++i) {
211: if (shells.shells[i] instanceof ActionTarget) {
212: lastshell = i + 1;
213: }
214: }
215:
216: Object penultimatebean = shells.shells[lastshell - 1];
217: String actionname = shells.segments[lastshell - 1];
218: // The only ActionTarget in the world is FlowActionProxyBean, we are not
219: // planning to keep it up
220: if (penultimatebean instanceof ActionTarget) {
221: Object returnvalue = ((ActionTarget) penultimatebean)
222: .invokeAction(actionname, knownvalue);
223: return returnvalue;
224: } else {
225: return darapplier.invokeBeanMethod(shells,
226: addressibleBeanModel);
227: }
228: }
229:
230: }
|