001: /***************************************************************
002: * This file is part of the [fleXive](R) project.
003: *
004: * Copyright (c) 1999-2008
005: * UCS - unique computing solutions gmbh (http://www.ucs.at)
006: * All rights reserved
007: *
008: * The [fleXive](R) project is free software; you can redistribute
009: * it and/or modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation;
011: * either version 2 of the License, or (at your option) any
012: * later version.
013: *
014: * The GNU General Public License can be found at
015: * http://www.gnu.org/copyleft/gpl.html.
016: * A copy is found in the textfile GPL.txt and important notices to the
017: * license from the author are found in LICENSE.txt distributed with
018: * these libraries.
019: *
020: * This library is distributed in the hope that it will be useful,
021: * but WITHOUT ANY WARRANTY; without even the implied warranty of
022: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
023: * GNU General Public License for more details.
024: *
025: * For further information about UCS - unique computing solutions gmbh,
026: * please see the company website: http://www.ucs.at
027: *
028: * For further information about [fleXive](R), please see the
029: * project website: http://www.flexive.org
030: *
031: *
032: * This copyright notice MUST APPEAR in all copies of the file!
033: ***************************************************************/package com.flexive.shared.scripting.groovy;
034:
035: import com.flexive.shared.CacheAdmin;
036: import com.flexive.shared.EJBLookup;
037: import com.flexive.shared.content.FxContent;
038: import com.flexive.shared.content.FxPK;
039: import com.flexive.shared.content.FxPropertyData;
040: import com.flexive.shared.exceptions.FxApplicationException;
041: import com.flexive.shared.exceptions.FxNotFoundException;
042: import com.flexive.shared.exceptions.FxInvalidParameterException;
043: import com.flexive.shared.interfaces.ContentEngine;
044: import com.flexive.shared.structure.FxEnvironment;
045: import com.flexive.shared.structure.FxPropertyAssignment;
046: import com.flexive.shared.value.FxValue;
047: import groovy.util.BuilderSupport;
048:
049: import java.util.Map;
050:
051: /**
052: * <p>
053: * A groovy builder for FxContent instances.
054: * </p>
055: * <p>Example:
056: * <pre>
057: * def builder = new GroovyContentBuilder("DOCUMENT")
058: * builder {
059: * title("Test article")
060: * Abstract("My abstract text")
061: * teaser {
062: * teaser_title("Teaser title")
063: * teaser_text("Teaser text")
064: * }
065: * box {
066: * box_title(new FxString(false, "Box title 1"))
067: * }
068: * box {
069: * box_title("Box title 2")
070: * box_text("Some box text")
071: * }
072: * }
073: * </pre>
074: * </p>
075: * @author Daniel Lichtenberger (daniel.lichtenberger@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
076: * @version $Rev: 193 $
077: */
078: public class GroovyContentBuilder extends BuilderSupport {
079: private class NodeInfo {
080: String xpath;
081: final Object value;
082:
083: public NodeInfo(String xpath, Object value) {
084: if (value == null && !xpath.endsWith("]")) {
085: // group node
086: String path;
087: try {
088: path = xpath
089: + "["
090: + (content.getGroupData(xpath)
091: .getOccurances() + 1) + "]";
092: } catch (FxApplicationException e) {
093: path = xpath + "[1]"; // first group
094: }
095: this .xpath = path;
096: } else if (!xpath.endsWith("]")) {
097: String path;
098: try {
099: final FxPropertyData propertyData = content
100: .getPropertyData(xpath);
101: int newIndex = propertyData.getOccurances() + 1;
102: if (!propertyData.getAssignment().getMultiplicity()
103: .isValid(newIndex)) {
104: // increase index, unless we're at the end of the multiplicity range
105: newIndex--;
106: }
107: path = xpath + "[" + newIndex + "]";
108: } catch (FxApplicationException e) {
109: path = xpath + "[1]";
110: }
111: this .xpath = path;
112: } else {
113: this .xpath = xpath;
114: }
115: this .value = value;
116: }
117:
118: public void addParentXPath(String parentXPath) {
119: xpath = parentXPath + xpath;
120: }
121:
122: @SuppressWarnings({"unchecked"})
123: public FxValue getValue() {
124: if (value instanceof FxValue) {
125: return (FxValue) value;
126: } else {
127: final FxValue fxValue = getPropertyAssignment(xpath)
128: .getEmptyValue();
129: fxValue.setDefaultTranslation(fxValue.fromString(value
130: .toString()));
131: return fxValue;
132: }
133: }
134: }
135:
136: private final FxContent content;
137: private final FxEnvironment environment = CacheAdmin
138: .getEnvironment();
139:
140: /**
141: * Create a new content builder that operates on the given content instance.
142: *
143: * @param content the target content
144: */
145: public GroovyContentBuilder(FxContent content) {
146: this .content = content;
147: }
148:
149: /**
150: * Create an empty content builder for the given type.
151: *
152: * @param typeName the content type name
153: * @throws com.flexive.shared.exceptions.FxApplicationException if the content could not be initialized
154: * by the content engine
155: */
156: public GroovyContentBuilder(String typeName)
157: throws FxApplicationException {
158: this .content = EJBLookup.getContentEngine()
159: .initialize(typeName);
160: }
161:
162: /**
163: * Create a content builder for the given instance.
164: *
165: * @param pk the object id (the content will be loaded through the content engine)
166: * @throws com.flexive.shared.exceptions.FxApplicationException if the content could not be loaded
167: */
168: public GroovyContentBuilder(FxPK pk) throws FxApplicationException {
169: this .content = EJBLookup.getContentEngine().load(pk);
170: }
171:
172: /**
173: * Return our content instance.
174: *
175: * @return our content instance.
176: */
177: public FxContent getContent() {
178: return content;
179: }
180:
181: /**
182: * {@inheritDoc}
183: */
184: @Override
185: protected void setParent(Object parent, Object child) {
186: try {
187: // if parent is a node info, use its xpath as prefix
188: final NodeInfo nodeInfo = (NodeInfo) child;
189: // add parent xpath to our node
190: nodeInfo
191: .addParentXPath(parent instanceof NodeInfo ? ((NodeInfo) parent).xpath
192: : "");
193: if (nodeInfo.value != null) {
194: content.setValue(nodeInfo.xpath, nodeInfo.getValue());
195: }
196: } catch (FxApplicationException e) {
197: throw e.asRuntimeException();
198: }
199: }
200:
201: /**
202: * {@inheritDoc}
203: */
204: @Override
205: protected Object createNode(Object name) {
206: return "call".equals(name) || "doCall".equals(name) ? name
207: : new NodeInfo(createXPath(name), null);
208: }
209:
210: /**
211: * {@inheritDoc}
212: */
213: @SuppressWarnings({"unchecked"})
214: @Override
215: protected Object createNode(Object name, Object value) {
216: final String xpath = createXPath(name);
217: return new NodeInfo(xpath, value);
218: }
219:
220: /**
221: * {@inheritDoc}
222: */
223: @Override
224: protected Object createNode(Object name, Map attributes) {
225: return null;
226: }
227:
228: /**
229: * {@inheritDoc}
230: */
231: @Override
232: protected Object createNode(Object name, Map attributes,
233: Object value) {
234: return null;
235: }
236:
237: private String createXPath(Object name) {
238: return (name instanceof String
239: && !((String) name).startsWith("/") ? "/" + name : name
240: .toString()).toUpperCase();
241: }
242:
243: private FxPropertyAssignment getPropertyAssignment(String xpath) {
244: return (FxPropertyAssignment) environment
245: .getAssignment(environment.getType(content.getTypeId())
246: .getName()
247: + xpath);
248: }
249: }
|