001: /*
002: * Copyright 2001-2006 C:1 Financial Services GmbH
003: *
004: * This software is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License Version 2.1, as published by the Free Software Foundation.
007: *
008: * This software is distributed in the hope that it will be useful,
009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
011: * Lesser General Public License for more details.
012: *
013: * You should have received a copy of the GNU Lesser General Public
014: * License along with this library; if not, write to the Free Software
015: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
016: */
017:
018: package de.finix.contelligent.components.query;
019:
020: import java.io.IOException;
021: import java.io.StringWriter;
022: import java.io.Writer;
023: import java.util.ArrayList;
024: import java.util.Collection;
025: import java.util.Collections;
026: import java.util.Iterator;
027: import java.util.LinkedList;
028: import java.util.List;
029: import java.util.Map;
030:
031: import org.apache.commons.xmlio.out.XMLStringWriter;
032: import org.apache.commons.xmlio.out.XMLWriter;
033: import org.apache.log4j.Logger;
034:
035: import de.finix.contelligent.CallData;
036: import de.finix.contelligent.Component;
037: import de.finix.contelligent.ComponentManager;
038: import de.finix.contelligent.ComponentNotFoundException;
039: import de.finix.contelligent.ComponentPath;
040: import de.finix.contelligent.ExternalRelationSource;
041: import de.finix.contelligent.ModificationVetoException;
042: import de.finix.contelligent.components.Folder;
043: import de.finix.contelligent.content.ContentProvider;
044: import de.finix.contelligent.event.ComponentEvent;
045: import de.finix.contelligent.event.ContelligentEvent;
046: import de.finix.contelligent.event.EventQueue;
047: import de.finix.contelligent.event.EventQueueListener;
048: import de.finix.contelligent.exception.ContelligentException;
049: import de.finix.contelligent.logging.LoggingService;
050: import de.finix.contelligent.render.DefaultRenderer;
051: import de.finix.contelligent.render.MissingParameterException;
052: import de.finix.contelligent.render.ParameterDescription;
053: import de.finix.contelligent.render.Renderable;
054: import de.finix.contelligent.render.Renderer;
055:
056: public class QueryResultProvider extends Folder implements Renderable,
057: Renderer, ExternalRelationSource {
058: private final static Logger log = LoggingService
059: .getLogger(QueryResultProvider.class);
060:
061: private ComponentPath query;
062:
063: private List cachedQueryResult;
064:
065: private boolean cacheOutput;
066:
067: private String cachedOutput;
068:
069: private EventQueueListener listener;
070:
071: public static final String QUERY_ELEMENT = "query";
072:
073: public static final String QUERY_RESULT_ELEMENT = "result";
074:
075: public static final String QUERY_RESULT_ENTRY_ELEMENT = "entry";
076:
077: public static final String QUERY_RESULT_ENTRY_KEY_ATTRIBUTE = "key";
078:
079: public void setQuery(ComponentPath query) {
080: this .query = query;
081: }
082:
083: public ComponentPath getQuery() {
084: return this .query;
085: }
086:
087: public boolean getCacheOutput() {
088: return cacheOutput;
089: }
090:
091: public void setCacheOutput(boolean cacheOutput) {
092: this .cacheOutput = cacheOutput;
093: }
094:
095: public void postCreate() throws Exception {
096: listener = new EventListener(this .getComponentContext()
097: .getPath());
098: EventQueue.getInstance().addListener(listener);
099: }
100:
101: /*
102: * (non-Javadoc)
103: *
104: * @see de.finix.contelligent.render.Renderable#getRenderer()
105: */
106: public Renderer getRenderer() {
107: return this ;
108: }
109:
110: /*
111: * (non-Javadoc)
112: *
113: * @see de.finix.contelligent.render.Renderer#getParameterDescription()
114: */
115: public ParameterDescription[] getParameterDescription() {
116: return null;
117: }
118:
119: /*
120: * (non-Javadoc)
121: *
122: * @see de.finix.contelligent.render.Renderer#render(java.io.Writer,
123: * java.util.Map, de.finix.contelligent.CallData)
124: */
125: public void render(Writer writer, Map parameterMap,
126: CallData callData) throws IOException,
127: MissingParameterException, ContelligentException {
128: // collect fragments
129: final boolean debugEnabled = log.isDebugEnabled();
130: final boolean production = callData.getActualManager().isRoot();
131: if (debugEnabled) {
132: log.debug("Start providing query");
133: }
134: ComponentManager manager = callData.getActualManager();
135: try {
136: Component content = manager.getSubcomponent(this , query,
137: callData);
138: if (content instanceof Query) {
139: List currentQuery = ((Query) content)
140: .getQueryResult(callData);
141: // check if query result has changed
142: synchronized (this ) {
143: if (!cacheOutput
144: || currentQuery != cachedQueryResult
145: || !production) {
146: XMLStringWriter xmlWriter = XMLStringWriter
147: .create();
148: xmlWriter.writeXMLDeclaration();
149: xmlWriter.writeStartTag(XMLWriter
150: .createStartTag(QUERY_ELEMENT));
151: if (production) {
152: cachedQueryResult = currentQuery;
153: }
154: // load QueryResultEntry-Components
155: List queryResultEntries = new ArrayList();
156: for (Iterator i = getSubcomponentNames(); i
157: .hasNext();) {
158: String childName = (String) i.next();
159: ComponentPath childPath = getComponentContext()
160: .getPath().append(childName);
161: try {
162: Component child = manager.getComponent(
163: childPath, callData);
164: if (child instanceof QueryResultEntry
165: || child instanceof StaticQueryResultEntry) {
166: queryResultEntries.add(child);
167: } else if (child instanceof Folder) {
168: for (Iterator j = ((Folder) child)
169: .getSubcomponentNames(); j
170: .hasNext();) {
171: ComponentPath folderChildPath = new ComponentPath(
172: (String) j.next());
173: try {
174: Component folderChild = manager
175: .getSubcomponent(
176: (Folder) child,
177: folderChildPath,
178: callData);
179: if (folderChild instanceof QueryResultEntry
180: || folderChild instanceof StaticQueryResultEntry) {
181: queryResultEntries
182: .add(folderChild);
183: }
184: } catch (ComponentNotFoundException e) {
185: log.error(
186: "Could not resolve child with path '"
187: + childPath
188: + "'", e);
189: }
190: }
191: }
192: } catch (ComponentNotFoundException e) {
193: log.error(
194: "Could not resolve child with path '"
195: + childPath + "'", e);
196: }
197: }
198: for (Iterator i = currentQuery.iterator(); i
199: .hasNext();) {
200: QueryResult result = (QueryResult) i.next();
201: ComponentPath childPath = null;
202: if (result instanceof ComponentQueryResult) {
203: childPath = ((ComponentQueryResult) result)
204: .getComponentPath();
205: }
206: xmlWriter
207: .writeStartTag(XMLWriter
208: .createStartTag(QUERY_RESULT_ELEMENT));
209: try {
210: // evaluate QueryResultEntries
211: for (Iterator qit = queryResultEntries
212: .iterator(); qit.hasNext();) {
213: Component queryResultEntry = (Component) qit
214: .next();
215: String renderedEntry = "";
216: if (queryResultEntry instanceof StaticQueryResultEntry) {
217: StaticQueryResultEntry entry = (StaticQueryResultEntry) queryResultEntry;
218: renderedEntry = entry
219: .getValue();
220: } else if (queryResultEntry instanceof QueryResultEntry) {
221: QueryResultEntry entry = (QueryResultEntry) queryResultEntry;
222: renderedEntry = entry.evaluate(
223: result, callData);
224: }
225:
226: // Write rendered entry
227: xmlWriter
228: .writeElementWithCData(
229: XMLWriter
230: .createStartTag(
231: QUERY_RESULT_ENTRY_ELEMENT,
232: QUERY_RESULT_ENTRY_KEY_ATTRIBUTE,
233: queryResultEntry
234: .getComponentContext()
235: .getPath()
236: .getName()),
237: renderedEntry,
238: XMLWriter
239: .createEndTag(QUERY_RESULT_ENTRY_ELEMENT));
240: }
241: xmlWriter
242: .writeEndTag(XMLWriter
243: .createEndTag(QUERY_RESULT_ELEMENT));
244: } catch (ComponentNotFoundException e) {
245: log
246: .error(
247: "Could not resolve component for content!",
248: e);
249: }
250: }
251: log.debug("Output calculated and cached!");
252: xmlWriter.writeEndTag(XMLWriter
253: .createEndTag(QUERY_ELEMENT));
254: cachedOutput = xmlWriter.toString();
255: }
256: // render cached output;
257: writer.write(cachedOutput);
258: }
259: } else {
260: log.error("Could not render component '" + query
261: + "', because it is not of type selection!");
262: }
263: } catch (ComponentNotFoundException e) {
264: log.error("Could not resolve content folder: '"
265: + query.toPath() + "'", e);
266: }
267: if (debugEnabled) {
268: log.debug("Query composed");
269: }
270: }
271:
272: /*
273: * (non-Javadoc)
274: *
275: * @see de.finix.contelligent.render.Renderer#getSensitiveCategories()
276: */
277: public Collection getSensitiveCategories() {
278: return null;
279: }
280:
281: /*
282: * (non-Javadoc)
283: *
284: * @see de.finix.contelligent.ExternalRelationSource#relatedPaths()
285: */
286: public List relatedPaths() {
287: LinkedList list = new LinkedList();
288: list.addLast(query);
289: return list;
290: }
291:
292: /*
293: * (non-Javadoc)
294: *
295: * @see de.finix.contelligent.ExternalRelationSource#relatedPaths(java.util.List)
296: */
297: public void relatedPaths(List newTargetPaths)
298: throws ModificationVetoException {
299: if (newTargetPaths == null || newTargetPaths.size() == 0
300: || newTargetPaths.size() > 1) {
301: throw new ModificationVetoException(
302: "illegal state - newTargetPaths: '"
303: + newTargetPaths + "'");
304: }
305: setQuery((ComponentPath) newTargetPaths.get(0));
306: }
307:
308: class EventListener implements EventQueueListener {
309: private ComponentPath path;
310:
311: public EventListener(ComponentPath path) {
312: this .path = path;
313: }
314:
315: public void onEvents(List eventList) {
316: for (Iterator i = eventList.iterator(); i.hasNext();) {
317: ContelligentEvent event = (ContelligentEvent) i.next();
318: if (event instanceof ComponentEvent) {
319: ComponentPath targetPath = ((ComponentEvent) event)
320: .getTargetPath();
321: if (targetPath.isSubPathOf(path)) {
322: synchronized (this) {
323: cachedQueryResult = null;
324: }
325: }
326: }
327: }
328: }
329: }
330:
331: }
|