Source Code Cross Referenced for SourceWritingTransformer.java in  » Content-Management-System » apache-lenya-2.0 » org » apache » cocoon » transformation » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Content Management System » apache lenya 2.0 » org.apache.cocoon.transformation 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Licensed to the Apache Software Foundation (ASF) under one or more
003:         * contributor license agreements.  See the NOTICE file distributed with
004:         * this work for additional information regarding copyright ownership.
005:         * The ASF licenses this file to You under the Apache License, Version 2.0
006:         * (the "License"); you may not use this file except in compliance with
007:         * the License.  You may obtain a copy of the License at
008:         *
009:         *      http://www.apache.org/licenses/LICENSE-2.0
010:         *
011:         * Unless required by applicable law or agreed to in writing, software
012:         * distributed under the License is distributed on an "AS IS" BASIS,
013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014:         * See the License for the specific language governing permissions and
015:         * limitations under the License.
016:         */
017:        package org.apache.cocoon.transformation;
018:
019:        import java.io.IOException;
020:        import java.io.OutputStream;
021:        import java.util.Map;
022:
023:        import org.apache.avalon.framework.configuration.Configuration;
024:        import org.apache.avalon.framework.configuration.ConfigurationException;
025:        import org.apache.avalon.framework.parameters.Parameters;
026:        import org.apache.avalon.framework.service.ServiceException;
027:        import org.apache.avalon.framework.service.ServiceManager;
028:        import org.apache.avalon.framework.service.ServiceSelector;
029:        import org.apache.cocoon.ProcessingException;
030:        import org.apache.cocoon.components.source.SourceUtil;
031:        import org.apache.cocoon.environment.SourceResolver;
032:        import org.apache.cocoon.serialization.Serializer;
033:        import org.apache.cocoon.xml.XMLUtils;
034:        import org.apache.cocoon.xml.dom.DOMStreamer;
035:        import org.apache.cocoon.xml.dom.DOMUtil;
036:        import org.apache.excalibur.source.ModifiableSource;
037:        import org.apache.excalibur.source.Source;
038:        import org.apache.excalibur.source.SourceException;
039:        import org.apache.excalibur.xml.dom.DOMParser;
040:        import org.apache.excalibur.xml.xpath.XPathProcessor;
041:        import org.w3c.dom.DOMException;
042:        import org.w3c.dom.Document;
043:        import org.w3c.dom.DocumentFragment;
044:        import org.w3c.dom.Node;
045:        import org.w3c.dom.NodeList;
046:        import org.xml.sax.Attributes;
047:        import org.xml.sax.SAXException;
048:
049:        /**
050:         * @cocoon.sitemap.component.documentation
051:         * This transformer allows you to output to a ModifiableSource.
052:         *
053:         * @cocoon.sitemap.component.name   sourcewriting
054:         * @cocoon.sitemap.component.logger sitemap.transformer.write-source
055:         *
056:         * This transformer allows you to output to a ModifiableSource.
057:         *
058:         * <p>Definition:</p>
059:         * <pre>
060:         * &lt;map:transformer     name="tofile"     src="org.apache.cocoon.transformation.SourceWritingTransformer"&gt;
061:         *   &lt;!-- 'xml' is the default Serializer (if your Source needs one, like for instance FileSource) --&gt;
062:         *   &lt;map:parameter name="serializer" value="xml"/&gt;
063:         * &lt;/map:transformer/&gt;
064:         * </pre>
065:         *
066:         * <p>Invocation:</p>
067:         * <pre>
068:         * &lt;map:transform type="tofile"&gt;
069:         *   &lt;map:parameter name="serializer" value="xml"/&gt;   &lt;!-- you can optionally override the serializer here --&gt;
070:         * &lt;/map:transform&gt;
071:         * </pre>
072:         *
073:         * <p>The Tags:</p>
074:         * <pre>
075:         * &lt;source:write create="[true]|false"&gt; - replaces the entire content of an existing asset, if @create is 'true' (default), a new asset will be created if one does not already exist.
076:         *     &lt;source:source&gt;The System ID of the asset to be written to&lt;/source:source&gt; - eg: "docs/blah.xml" or "context://blah.xml" etc.
077:         *     &lt;source:path&gt;[Optional] XPath to specify how your content is wrapped&lt;/source:path&gt; - eg: "doc" (your content is placed inside a &lt;doc/&gt; root tag). NOTE: if this value is omitted, your content MUST have only ONE top-level node.
078:         *     &lt;source:fragment&gt;The XML Fragment to be written&lt;/source:fragment&gt; - eg: "&lt;foo&gt;&lt;bar id="dogcow"/&gt;&lt;/foo&gt;" or "&lt;foo/&gt;&lt;bar&gt;&lt;dogcow/&gt;&lt;bar/&gt;" etc. NOTE: the second example type, can only be used when the &lt;source:path/&gt; tag has been specified.
079:         * &lt;source:write&gt;
080:         *
081:         * &lt;source:insert create="[true]|false" overwrite="[true]|false"&gt; - inserts content into an existing asset, if @create is 'true' (default), a new asset will be created if one does not already exist. If @overwrite is set to 'true' the data is only inserted if the node specified by the 'replacePath' does not exists.
082:         *     &lt;source:source&gt;The System ID of the asset to be written to&lt;/source:source&gt; - eg: "docs/blah.xml" or "context://blah.xml" etc.
083:         *     &lt;source:path&gt;XPath specifying the node into which the content is inserted&lt;/source:path&gt; - eg: "doc" (your content is appended as the last child of the &lt;doc/&gt; root tag), or "doc/section[3]". NOTE: this tag is required in &lt;source:insert/&gt; unlike &lt;source:write/&gt; where it is optional.
084:         *     &lt;source:replace&gt;[Optional] XPath (relative to &lt;source:path/&gt;) to the node that is replaced by your new content&lt;/source:replace&gt; - eg: "foo/bar/dogcow/@status='cut'" (is equivalent to this in XSLT: select="foo[bar/dogcow/@status='cut']").
085:         *     &lt;source:reinsert&gt;[Optional] The XPath (relative to &lt;source:replace/&gt;) to backup the overwritten node to&lt;/source:reinsert&gt; - eg: "foo/versions" or "/doc/versions/foo". NOTE: If specified and a node is replaced, all children of this replaced node will be reinserted at the given path.
086:         *     &lt;source:fragment&gt;The XML Fragment to be written&lt;/source:fragment&gt; - eg: "&lt;foo&gt;&lt;bar id="dogcow"/&gt;&lt;/foo&gt;" or "&lt;foo/&gt;&lt;bar&gt;&lt;dogcow/&gt;&lt;bar/&gt;" etc.
087:         * &lt;source:insert&gt;
088:         *
089:         * &lt;source:delete &gt; - deletes an existing asset.
090:         *     &lt;source:source&gt;The System ID of the asset to be deleted&lt;/source:source&gt; - eg: "docs/blah.xml" or "context://blah.xml" etc.
091:         *     &lt;source:path&gt;[Ignored] XPath to specify how your content is wrapped&lt;/source:path&gt;
092:         *     &lt;source:fragment&gt;[Ignored]The XML Fragment to be written&lt;/source:fragment&gt;
093:         * &lt;source:delete&gt;
094:         * </pre>
095:         *
096:         *
097:         * <p>Input XML document example (write):</p>
098:         * <pre>
099:         * &lt;page&gt;
100:         *   ...
101:         *   &lt;source:write xmlns:source="http://apache.org/cocoon/source/1.0"&gt;
102:         *     &lt;source:source&gt;context://doc/editable/my.xml&lt;/source:source&gt;
103:         *     &lt;source:fragment&gt;&lt;page&gt;
104:         *       &lt;title&gt;Hello World&lt;/title&gt;
105:         *       &lt;content&gt;
106:         *         &lt;p&gt;This is my first paragraph.&lt;/p&gt;
107:         *       &lt;/content&gt;
108:         *     &lt;/page&gt;&lt;/source:fragment&gt;
109:         *   &lt;/source:write&gt;
110:         *   ...
111:         * &lt;/page&gt;
112:         * </pre>
113:         *
114:         * <p>Input XML document example (insert at end):</p>
115:         * <pre>
116:         * &lt;page&gt;
117:         *   ...
118:         *   &lt;source:insert xmlns:source="http://apache.org/cocoon/source/1.0"&gt;
119:         *     &lt;source:source&gt;context://doc/editable/my.xml&lt;/source:source&gt;
120:         *     &lt;source:path&gt;page/content&lt;/source:path&gt;
121:         *     &lt;source:fragment&gt;
122:         *       &lt;p&gt;This paragraph gets &lt;emp&gt;inserted&lt;/emp&gt;.&lt;/p&gt;
123:         *       &lt;p&gt;With this one, at the end of the content.&lt;/p&gt;
124:         *     &lt;/source:fragment&gt;
125:         *   &lt;/source:insert&gt;
126:         *   ...
127:         * &lt;/page&gt;
128:         * </pre>
129:         *
130:         * <p>Input XML document example (insert at beginning):</p>
131:         * <pre>
132:         * &lt;page&gt;
133:         *   ...
134:         *   &lt;source:insert&gt;
135:         *     &lt;source:source&gt;context://doc/editable/my.xml&lt;/source:source&gt;
136:         *     &lt;source:path&gt;page&lt;/source:path&gt;
137:         *     &lt;source:replace&gt;content&lt;/source:replace&gt;
138:         *     &lt;source:reinsert&gt;content&lt;/source:reinsert&gt;
139:         *     &lt;source:fragment&gt;
140:         *       &lt;content&gt;
141:         *         &lt;p&gt;This new paragraph gets inserted &lt;emp&gt;before&lt;/emp&gt; the other ones.&lt;/p&gt;
142:         *       &lt;/content&gt;
143:         *     &lt;/source:fragment&gt;
144:         *    &lt;source:insert&gt;
145:         *   ...
146:         * &lt;/page&gt;
147:         * </pre>
148:         *
149:         * <p>Input XML document example (replace):</p>
150:         * <pre>
151:         * &lt;page&gt;
152:         *   ...
153:         *   &lt;source:insert xmlns:source="http://apache.org/cocoon/source/1.0"&gt;
154:         *     &lt;source:source&gt;context://doc/editable/my.xml"&lt;/source:source&gt;
155:         *     &lt;source:path&gt;page/content&lt;/source:path&gt;
156:         *     &lt;source:replace&gt;p[1]&lt;/source:replace&gt;
157:         *     &lt;source:fragment&gt;
158:         *       &lt;p&gt;This paragraph &lt;emp&gt;replaces&lt;/emp&gt; the first paragraph.&lt;/p&gt;
159:         *     &lt;/source:fragment&gt;
160:         *   &lt;/source:insert&gt;
161:         *   ...
162:         * &lt;/page&gt;
163:         * </pre>
164:         *
165:         * <p>Output XML document example:</p>
166:         * <pre>
167:         * &lt;page&gt;
168:         *   ...
169:         *   &lt;sourceResult xmlns:source="http://apache.org/cocoon/source/1.0"&gt;
170:         *     &lt;action&gt;new|overwritten|none&lt;/action&gt;
171:         *     &lt;behaviour&gt;write|insert&lt;behaviour&gt;
172:         *     &lt;execution&gt;success|failure&lt;/execution&gt;
173:         *     &lt;serializer&gt;xml&lt;/serializer&gt;
174:         *     &lt;source&gt;file:/source/specific/path/to/context/doc/editable/my.xml&lt;/source&gt;
175:         *   &lt;/sourceResult&gt;
176:         *   ...
177:         * &lt;/page&gt;
178:         * </pre>
179:         *
180:         *
181:         * The XPath specification is very complicated. So here is an example for the sitemap:
182:         * <pre>
183:         * &lt;page xmlns:source="http://apache.org/cocoon/source/1.0"&gt;
184:         *   ...
185:         * &lt;source:insert&gt;
186:         *   &lt;source:source&gt;sitemap.xmap&lt;/source:source&gt;
187:         *   &lt;source:path&gt;/*[namespace-uri()="http://apache.org/cocoon/sitemap/1.0" and local-name()="sitemap"]/*[namespace-uri()="http://apache.org/cocoon/sitemap/1.0" and local-name()="components"]/*[namespace-uri()="http://apache.org/cocoon/sitemap/1.0" and local-name()="generators"]&lt;/source:path&gt;
188:         *   &lt;source:fragment&gt;
189:         *	  	&lt;generator name="file" xmln="http://apache.org/cocoon/sitemap/1.0"&gt;
190:         *			&lt;test/&gt;
191:         *		&lt;/generator&gt;
192:         *   &lt;/source:fragment&gt;
193:         *   &lt;source:replace&gt;*[namespace-uri()="http://apache.org/cocoon/sitemap/1.0" and local-name()="generator" and attribute::name="file"]&lt;/source:replace&gt;
194:         * &lt;/source:insert&gt;
195:         *   ...
196:         * &lt;/page&gt;
197:         * </pre>
198:         *
199:         * <p>This insert replaces (if it exists) the file generator definition with a new one.
200:         * As the sitemap uses namespaces the XPath for the generator is rather complicated.
201:         * Due to this it is necessary that the node specified by path exists if namespaces
202:         * are used! Otherwise a node with the name * would be created...</p>
203:         *
204:         *  <p>The create attribute of insert. If this is set
205:         *  to true (default is true), the file is created if it does not exists.
206:         *  If it is set to false, it is not created, making insert a real insert.
207:         *  create is only usable for files!</p>
208:         *  <p>In addition the overwrite attribute is used to check if replacing is allowed.
209:         *  If overwrite is true (the default) the node is replaced. If it is false
210:         *  the node is not inserted if the replace node is available.</p>
211:         *
212:         *  <p>[JQ] - the way I understand this, looking at the code:
213:         *  <pre>
214:         *   if 'replace' is not specified, your 'fragment' is appended as a child of 'path'.
215:         *   if 'replace' is specified and it exists and 'overwrite' is true, your 'fragment' is inserted in 'path', before 'replace' and then 'replace' is deleted.
216:         *   if 'replace' is specified and it exists and 'overwrite' is false, no action occurs.
217:         *   if 'replace' is specified and it does not exist and 'overwrite' is true, your 'fragment' is appended as a child of 'path'.
218:         *   if 'replace' is specified and it does not exist and 'overwrite' is false, your 'fragment' is appended as a child of 'path'.
219:         *   if 'reinsert' is specified and it does not exist, no action occurs.
220:         *  </pre></p>
221:         *
222:         * The &lt;source:reinsert&gt; option can be used to
223:         * reinsert a replaced node at a given path in the new fragment.
224:         *
225:         * <b>
226:         * TODO: Use the serializer instead of the XMLUtils for inserting of fragments<br/>
227:         * TODO: Add a &lt;source:before/&gt; tag.
228:         * </b>
229:         *
230:         * @author <a href="mailto:cziegeler@s-und-n.de">Carsten Ziegeler</a>
231:         * @author <a href="mailto:jeremy@apache.org">Jeremy Quinn</a>
232:         * @author <a href="mailto:gianugo@apache.org">Gianugo Rabellino</a>
233:         * @version $Id: SourceWritingTransformer.java 433543 2006-08-22 06:22:54Z crossley $
234:         */
235:        public class SourceWritingTransformer extends AbstractSAXTransformer {
236:
237:            public static final String SWT_URI = "http://apache.org/cocoon/source/1.0";
238:            public static final String DEFAULT_SERIALIZER = "xml";
239:
240:            /** incoming elements */
241:            public static final String WRITE_ELEMENT = "write";
242:            public static final String INSERT_ELEMENT = "insert";
243:            public static final String PATH_ELEMENT = "path";
244:            public static final String FRAGMENT_ELEMENT = "fragment";
245:            public static final String REPLACE_ELEMENT = "replace";
246:            public static final String DELETE_ELEMENT = "delete";
247:            public static final String SOURCE_ELEMENT = "source";
248:            public static final String REINSERT_ELEMENT = "reinsert";
249:            /** outgoing elements */
250:            public static final String RESULT_ELEMENT = "sourceResult";
251:            public static final String EXECUTION_ELEMENT = "execution";
252:            public static final String BEHAVIOUR_ELEMENT = "behaviour";
253:            public static final String ACTION_ELEMENT = "action";
254:            public static final String MESSAGE_ELEMENT = "message";
255:            public static final String SERIALIZER_ELEMENT = "serializer";
256:            /** main (write or insert) tag attributes */
257:            public static final String SERIALIZER_ATTRIBUTE = "serializer";
258:            public static final String CREATE_ATTRIBUTE = "create";
259:            public static final String OVERWRITE_ATTRIBUTE = "overwrite";
260:            /** results */
261:            public static final String RESULT_FAILED = "failed";
262:            public static final String RESULT_SUCCESS = "success";
263:            public static final String ACTION_NONE = "none";
264:            public static final String ACTION_NEW = "new";
265:            public static final String ACTION_OVER = "overwritten";
266:            public static final String ACTION_DELETE = "deleted";
267:            /** The current state */
268:            private static final int STATE_OUTSIDE = 0;
269:            private static final int STATE_INSERT = 1;
270:            private static final int STATE_PATH = 3;
271:            private static final int STATE_FRAGMENT = 4;
272:            private static final int STATE_REPLACE = 5;
273:            private static final int STATE_FILE = 6;
274:            private static final int STATE_REINSERT = 7;
275:            private static final int STATE_WRITE = 8;
276:            private static final int STATE_DELETE = 9;
277:            private int state;
278:            private int parent_state;
279:
280:            /** The configured serializer name */
281:            protected String configuredSerializerName;
282:
283:            /** The XPath processor */
284:            protected XPathProcessor xpathProcessor;
285:
286:            /**
287:             * Constructor. Set the namespace.
288:             */
289:            public SourceWritingTransformer() {
290:                this .defaultNamespaceURI = SWT_URI;
291:            }
292:
293:            /**
294:             * Get the current <code>Configuration</code> instance used by this
295:             * <code>Configurable</code>.
296:             */
297:            public void configure(Configuration configuration)
298:                    throws ConfigurationException {
299:                super .configure(configuration);
300:                this .configuredSerializerName = configuration.getChild(
301:                        SERIALIZER_ATTRIBUTE).getValue(DEFAULT_SERIALIZER);
302:            }
303:
304:            /**
305:             * Get the <code>Parameter</code> called "serializer" from the
306:             * <code>Transformer</code> invocation.
307:             */
308:            public void setup(SourceResolver resolver, Map objectModel,
309:                    String src, Parameters par) throws ProcessingException,
310:                    SAXException, IOException {
311:                super .setup(resolver, objectModel, src, par);
312:
313:                this .configuredSerializerName = par.getParameter(
314:                        SERIALIZER_ATTRIBUTE, this .configuredSerializerName);
315:                this .state = STATE_OUTSIDE;
316:            }
317:
318:            /**
319:             * Receive notification of the beginning of an element.
320:             *
321:             * @param uri The Namespace URI, or the empty string if the element has no
322:             *            Namespace URI or if Namespace
323:             *            processing is not being performed.
324:             * @param name The local name (without prefix), or the empty string if
325:             *            Namespace processing is not being performed.
326:             * @param raw The raw XML 1.0 name (with prefix), or the empty string if
327:             *            raw names are not available.
328:             * @param attr The attributes attached to the element. If there are no
329:             *            attributes, it shall be an empty Attributes object.
330:             */
331:            public void startTransformingElement(String uri, String name,
332:                    String raw, Attributes attr) throws SAXException,
333:                    IOException, ProcessingException {
334:                if (getLogger().isDebugEnabled()) {
335:                    getLogger().debug(
336:                            "Start transforming element. uri=" + uri
337:                                    + ", name=" + name + ", raw=" + raw
338:                                    + ", attr=" + attr);
339:                }
340:
341:                // Element: insert
342:                if (this .state == STATE_OUTSIDE
343:                        && (name.equals(INSERT_ELEMENT) || name
344:                                .equals(WRITE_ELEMENT))) {
345:
346:                    this .state = (name.equals(INSERT_ELEMENT) ? STATE_INSERT
347:                            : STATE_WRITE);
348:                    this .parent_state = this .state;
349:                    if (attr.getValue(CREATE_ATTRIBUTE) != null
350:                            && attr.getValue(CREATE_ATTRIBUTE).equals("false")) {
351:                        this .stack.push("false");
352:                    } else {
353:                        this .stack.push("true"); // default value
354:                    }
355:                    if (attr.getValue(OVERWRITE_ATTRIBUTE) != null
356:                            && attr.getValue(OVERWRITE_ATTRIBUTE).equals(
357:                                    "false")) {
358:                        this .stack.push("false");
359:                    } else {
360:                        this .stack.push("true"); // default value
361:                    }
362:                    this .stack.push(attr.getValue(SERIALIZER_ATTRIBUTE));
363:                    this .stack.push("END");
364:
365:                    // Element: delete
366:                } else if (this .state == STATE_OUTSIDE
367:                        && name.equals(DELETE_ELEMENT)) {
368:                    this .state = STATE_DELETE;
369:                    this .parent_state = state;
370:                    this .stack.push("END");
371:                    // Element: file
372:                } else if (name.equals(SOURCE_ELEMENT)
373:                        && (this .state == STATE_INSERT
374:                                || this .state == STATE_WRITE || this .state == STATE_DELETE)) {
375:                    this .state = STATE_FILE;
376:                    this .startTextRecording();
377:
378:                    // Element: path
379:                } else if (name.equals(PATH_ELEMENT)
380:                        && (this .state == STATE_INSERT
381:                                || this .state == STATE_WRITE || this .state == STATE_DELETE)) {
382:                    this .state = STATE_PATH;
383:                    this .startTextRecording();
384:
385:                    // Element: replace
386:                } else if (name.equals(REPLACE_ELEMENT)
387:                        && this .state == STATE_INSERT) {
388:                    this .state = STATE_REPLACE;
389:                    this .startTextRecording();
390:
391:                    // Element: fragment
392:                } else if (name.equals(FRAGMENT_ELEMENT)
393:                        && (this .state == STATE_INSERT
394:                                || this .state == STATE_WRITE || this .state == STATE_DELETE)) {
395:                    this .state = STATE_FRAGMENT;
396:                    this .startRecording();
397:
398:                    // Element: reinsert
399:                } else if (name.equals(REINSERT_ELEMENT)
400:                        && this .state == STATE_INSERT) {
401:                    this .state = STATE_REINSERT;
402:                    this .startTextRecording();
403:
404:                } else {
405:                    super .startTransformingElement(uri, name, raw, attr);
406:                }
407:            }
408:
409:            /**
410:             * Receive notification of the end of an element.
411:             *
412:             * @param uri The Namespace URI, or the empty string if the element has no
413:             *            Namespace URI or if Namespace
414:             *            processing is not being performed.
415:             * @param name The local name (without prefix), or the empty string if
416:             *            Namespace processing is not being performed.
417:             * @param raw The raw XML 1.0 name (with prefix), or the empty string if
418:             *            raw names are not available.
419:             */
420:            public void endTransformingElement(String uri, String name,
421:                    String raw) throws SAXException, IOException,
422:                    ProcessingException {
423:                if (getLogger().isDebugEnabled()) {
424:                    getLogger().debug(
425:                            "End transforming element. uri=" + uri + ", name="
426:                                    + name + ", raw=" + raw);
427:                }
428:
429:                if ((name.equals(INSERT_ELEMENT) && this .state == STATE_INSERT)
430:                        || (name.equals(WRITE_ELEMENT) && this .state == STATE_WRITE)) {
431:
432:                    // get the information from the stack
433:                    DocumentFragment fragment = null;
434:                    String tag;
435:                    String sourceName = null;
436:                    String path = (this .state == STATE_INSERT ? null : "/");
437:                    // source:write's path can be empty
438:                    String replacePath = null;
439:                    String reinsert = null;
440:                    do {
441:                        tag = (String) this .stack.pop();
442:                        if (tag.equals("PATH")) {
443:                            path = (String) this .stack.pop();
444:                        } else if (tag.equals("FILE")) {
445:                            sourceName = (String) this .stack.pop();
446:                        } else if (tag.equals("FRAGMENT")) {
447:                            fragment = (DocumentFragment) this .stack.pop();
448:                        } else if (tag.equals("REPLACE")) {
449:                            replacePath = (String) this .stack.pop();
450:                        } else if (tag.equals("REINSERT")) {
451:                            reinsert = (String) this .stack.pop();
452:                        }
453:                    } while (!tag.equals("END"));
454:
455:                    final String localSerializer = (String) this .stack.pop();
456:                    final boolean overwrite = this .stack.pop().equals("true");
457:                    final boolean create = this .stack.pop().equals("true");
458:
459:                    this .insertFragment(sourceName, path, fragment,
460:                            replacePath, create, overwrite, reinsert,
461:                            localSerializer, name);
462:
463:                    this .state = STATE_OUTSIDE;
464:
465:                    // Element: delete
466:                } else if (name.equals(DELETE_ELEMENT)
467:                        && this .state == STATE_DELETE) {
468:                    String sourceName = null;
469:                    String tag;
470:                    do {
471:                        tag = (String) this .stack.pop();
472:                        if (tag.equals("FILE")) {
473:                            sourceName = (String) this .stack.pop();
474:                        } else if (tag.equals("FRAGMENT")) {
475:                            //Get rid of it
476:                            this .stack.pop();
477:                        }
478:                    } while (!tag.equals("END"));
479:
480:                    this .deleteSource(sourceName);
481:                    this .state = STATE_OUTSIDE;
482:                    // Element: file
483:                } else if (name.equals(SOURCE_ELEMENT)
484:                        && this .state == STATE_FILE) {
485:                    this .state = this .parent_state;
486:                    this .stack.push(this .endTextRecording());
487:                    this .stack.push("FILE");
488:
489:                    // Element: path
490:                } else if (name.equals(PATH_ELEMENT)
491:                        && this .state == STATE_PATH) {
492:                    this .state = this .parent_state;
493:                    this .stack.push(this .endTextRecording());
494:                    this .stack.push("PATH");
495:
496:                    // Element: replace
497:                } else if (name.equals(REPLACE_ELEMENT)
498:                        && this .state == STATE_REPLACE) {
499:                    this .state = this .parent_state;
500:                    this .stack.push(this .endTextRecording());
501:                    this .stack.push("REPLACE");
502:
503:                    // Element: fragment
504:                } else if (name.equals(FRAGMENT_ELEMENT)
505:                        && this .state == STATE_FRAGMENT) {
506:                    this .state = this .parent_state;
507:                    this .stack.push(this .endRecording());
508:                    this .stack.push("FRAGMENT");
509:
510:                    // Element: reinsert
511:                } else if (name.equals(REINSERT_ELEMENT)
512:                        && this .state == STATE_REINSERT) {
513:                    this .state = this .parent_state;
514:                    this .stack.push(this .endTextRecording());
515:                    this .stack.push("REINSERT");
516:
517:                    // default
518:                } else {
519:                    super .endTransformingElement(uri, name, raw);
520:                }
521:            }
522:
523:            /**
524:             * Deletes a source
525:             * @param systemID
526:             */
527:            private void deleteSource(String systemID)
528:                    throws ProcessingException, IOException, SAXException {
529:                Source source = null;
530:                try {
531:                    source = resolver.resolveURI(systemID);
532:                    if (!(source instanceof  ModifiableSource)) {
533:                        throw new ProcessingException("Source '" + systemID
534:                                + "' is not writeable.");
535:                    }
536:
537:                    ((ModifiableSource) source).delete();
538:                    reportResult("none", "delete",
539:                            "source deleted successfully", systemID,
540:                            RESULT_SUCCESS, ACTION_DELETE);
541:                } catch (SourceException se) {
542:                    if (getLogger().isDebugEnabled()) {
543:                        getLogger().debug("FAIL exception: " + se, se);
544:                    }
545:                    reportResult("none", "delete", "unable to delete source: "
546:                            + se.getMessage(), systemID, RESULT_FAILED,
547:                            ACTION_DELETE);
548:                } finally {
549:                    resolver.release(source);
550:                }
551:            }
552:
553:            /**
554:             * Insert a fragment into a file.
555:             * The file is loaded by the resource connector.
556:             *
557:             * @param systemID The name of the xml file.
558:             * @param path   The XPath specifying the node under which the data is inserted
559:             * @param fragment The data to be inserted.
560:             * @param replacePath Optional XPath relative to <CODE>path</CODE>. This path
561:             *                    can specify a node which will be removed if it exists.
562:             *                    So insertFragment can be used as a replace utility.
563:             * @param create      If the file does not exists and this is set to
564:             *                    <CODE>false</CODE> nothing is inserted. If it is set
565:             *                    to <CODE>true</CODE> the file is created and the data
566:             *                    is inserted.
567:             * @param overwrite   If this is set to <CODE>true</CODE> the data is only
568:             *                    inserted if the node specified by the <CODE>replacePath</CODE>
569:             *                    does not exists.
570:             * @param reinsertPath If specified and a node is replaced , all children of
571:             *                     this replaced node will be reinserted at the given path.
572:             * @param localSerializer  The serializer used to serialize the XML
573:             * @param tagname     The name of the tag that triggered me 'insert' or 'write'
574:             */
575:            protected void insertFragment(String systemID, String path,
576:                    DocumentFragment fragment, String replacePath,
577:                    boolean create, boolean overwrite, String reinsertPath,
578:                    String localSerializer, String tagname)
579:                    throws SAXException, IOException, ProcessingException {
580:                // no sync req
581:                if (getLogger().isDebugEnabled()) {
582:                    getLogger().debug(
583:                            "Insert fragment. systemID="
584:                                    + systemID
585:                                    + ", path="
586:                                    + path
587:                                    + ", replace="
588:                                    + replacePath
589:                                    + ", create="
590:                                    + create
591:                                    + ", overwrite="
592:                                    + overwrite
593:                                    + ", reinsert="
594:                                    + reinsertPath
595:                                    + ", fragment="
596:                                    + (fragment == null ? "null" : XMLUtils
597:                                            .serializeNode(fragment)));
598:                }
599:
600:                // test parameter
601:                if (systemID == null) {
602:                    throw new ProcessingException(
603:                            "insertFragment: systemID is required.");
604:                }
605:                if (path == null) {
606:                    throw new ProcessingException(
607:                            "insertFragment: path is required.");
608:                }
609:                if (path.startsWith("/")) {
610:                    path = path.substring(1);
611:                }
612:                if (fragment == null) {
613:                    throw new ProcessingException(
614:                            "insertFragment: fragment is required.");
615:                }
616:
617:                // first: read the source as a DOM
618:                Source source = null;
619:                Document resource = null;
620:                boolean failed = true;
621:                boolean exists = false;
622:                String message = "";
623:                String target = systemID;
624:                try {
625:                    source = this .resolver.resolveURI(systemID);
626:                    if (!(source instanceof  ModifiableSource)) {
627:                        throw new ProcessingException("Source '" + systemID
628:                                + "' is not writeable.");
629:                    }
630:                    ModifiableSource ws = (ModifiableSource) source;
631:                    exists = ws.exists();
632:                    target = source.getURI();
633:
634:                    // Insert?
635:                    if (exists && this .state == STATE_INSERT) {
636:                        message = "content inserted at: " + path;
637:                        resource = SourceUtil.toDOM(source);
638:                        // import the fragment
639:                        Node importNode = resource.importNode(fragment, true);
640:                        // get the node
641:                        Node parent = DOMUtil.selectSingleNode(resource, path,
642:                                this .xpathProcessor);
643:
644:                        // replace?
645:                        if (replacePath != null) {
646:                            try {
647:                                Node replaceNode = DOMUtil.getSingleNode(
648:                                        parent, replacePath,
649:                                        this .xpathProcessor);
650:                                // now get the parent of this node until it is the parent node for insertion
651:                                while (replaceNode != null
652:                                        && !replaceNode.getParentNode().equals(
653:                                                parent)) {
654:                                    replaceNode = replaceNode.getParentNode();
655:                                }
656:
657:                                if (replaceNode != null) {
658:                                    if (overwrite) {
659:                                        if (parent.getNodeType() == Node.DOCUMENT_NODE) {
660:                                            // replacing of the document element is not allowed
661:                                            resource = newDocument();
662:                                            resource.appendChild(resource
663:                                                    .importNode(importNode,
664:                                                            true));
665:                                            parent = resource;
666:                                            replaceNode = resource.importNode(
667:                                                    replaceNode, true);
668:                                        } else {
669:                                            parent.replaceChild(importNode,
670:                                                    replaceNode);
671:                                        }
672:                                        message += ", replacing: "
673:                                                + replacePath;
674:                                        if (reinsertPath != null) {
675:                                            Node insertAt = DOMUtil
676:                                                    .getSingleNode(parent,
677:                                                            reinsertPath,
678:                                                            this .xpathProcessor);
679:                                            if (insertAt != null) {
680:                                                while (replaceNode
681:                                                        .hasChildNodes()) {
682:                                                    insertAt
683:                                                            .appendChild(replaceNode
684:                                                                    .getFirstChild());
685:                                                }
686:                                            } else { // reinsert point null
687:                                                message = "replace failed, could not find your reinsert path: "
688:                                                        + reinsertPath;
689:                                                resource = null;
690:                                            }
691:                                        }
692:                                    } else { // overwrite was false
693:                                        message = "replace failed, no overwrite allowed.";
694:                                        resource = null;
695:                                    }
696:                                } else { // specified replaceNode was not found
697:                                    parent.appendChild(importNode);
698:                                }
699:                            } catch (javax.xml.transform.TransformerException sax) {
700:                                throw new ProcessingException(
701:                                        "TransformerException: " + sax, sax);
702:                            }
703:                        } else { // no replace path, just do an insert at end
704:                            parent.appendChild(importNode);
705:                        }
706:
707:                        // Create?
708:                    } else if (create) {
709:                        // Create new document
710:                        resource = newDocument();
711:
712:                        // Import the fragment
713:                        Node importNode = resource.importNode(fragment, true);
714:
715:                        if (path.length() == 0) {
716:                            // Parent node is document itself
717:                            NodeList nodes = importNode.getChildNodes();
718:                            for (int i = 0; i < nodes.getLength();) {
719:                                Node node = nodes.item(i);
720:                                switch (node.getNodeType()) {
721:                                case Node.ELEMENT_NODE:
722:                                    // May throw exception if fragment has more than one element
723:                                    resource.appendChild(node);
724:                                    break;
725:
726:                                case Node.DOCUMENT_TYPE_NODE:
727:                                case Node.PROCESSING_INSTRUCTION_NODE:
728:                                case Node.COMMENT_NODE:
729:                                    resource.appendChild(node);
730:                                    break;
731:
732:                                default:
733:                                    // Ignore all other nodes
734:                                    i++;
735:                                    break;
736:                                }
737:                            }
738:                            message = "entire source overwritten";
739:
740:                        } else {
741:                            // Get the parent node
742:                            Node parent = DOMUtil.selectSingleNode(resource,
743:                                    path, this .xpathProcessor);
744:                            // Add a fragment
745:                            parent.appendChild(importNode);
746:                            message = "content appended to: " + path;
747:                        }
748:
749:                        // Oops: Document does not exist and create is not allowed.
750:                    } else {
751:                        message = "create not allowed";
752:                        resource = null;/**/
753:                    }
754:
755:                    // Write source
756:                    if (resource != null) {
757:                        resource.normalize();
758:                        // use serializer
759:                        if (localSerializer == null) {
760:                            localSerializer = this .configuredSerializerName;
761:                        }
762:
763:                        if (localSerializer != null) {
764:                            // Lookup the Serializer
765:                            ServiceSelector selector = null;
766:                            Serializer serializer = null;
767:                            OutputStream oStream = null;
768:                            try {
769:                                selector = (ServiceSelector) manager
770:                                        .lookup(Serializer.ROLE + "Selector");
771:                                serializer = (Serializer) selector
772:                                        .select(localSerializer);
773:                                oStream = ws.getOutputStream();
774:                                serializer.setOutputStream(oStream);
775:                                DOMStreamer streamer = new DOMStreamer(
776:                                        serializer);
777:                                streamer.stream(resource);
778:                            } finally {
779:                                if (oStream != null) {
780:                                    oStream.flush();
781:                                    try {
782:                                        oStream.close();
783:                                        failed = false;
784:                                    } catch (Throwable t) {
785:                                        if (getLogger().isDebugEnabled()) {
786:                                            getLogger().debug(
787:                                                    "FAIL (oStream.close) exception"
788:                                                            + t, t);
789:                                        }
790:                                        throw new ProcessingException(
791:                                                "Could not process your document.",
792:                                                t);
793:                                    } finally {
794:                                        if (selector != null) {
795:                                            selector.release(serializer);
796:                                            this .manager.release(selector);
797:                                        }
798:                                    }
799:                                }
800:                            }
801:                        } else {
802:                            if (getLogger().isDebugEnabled()) {
803:                                getLogger().debug("ERROR: No serializer");
804:                            }
805:                            //throw new ProcessingException("No serializer specified for writing to source " + systemID);
806:                            message = "That source requires a serializer, please add the appropirate tag to your code.";
807:                        }
808:                    }
809:                } catch (DOMException de) {
810:                    if (getLogger().isDebugEnabled()) {
811:                        getLogger().debug("FAIL exception: " + de, de);
812:                    }
813:                    message = "There was a problem manipulating your document: "
814:                            + de;
815:                } catch (ServiceException ce) {
816:                    if (getLogger().isDebugEnabled()) {
817:                        getLogger().debug("FAIL exception: " + ce, ce);
818:                    }
819:                    message = "There was a problem looking up a component: "
820:                            + ce;
821:                } catch (SourceException se) {
822:                    if (getLogger().isDebugEnabled()) {
823:                        getLogger().debug("FAIL exception: " + se, se);
824:                    }
825:                    message = "There was a problem resolving that source: ["
826:                            + systemID + "] : " + se;
827:                } finally {
828:                    this .resolver.release(source);
829:                }
830:
831:                // Report result
832:                String result = (failed) ? RESULT_FAILED : RESULT_SUCCESS;
833:                String action = ACTION_NONE;
834:                if (!failed) {
835:                    action = (exists) ? ACTION_OVER : ACTION_NEW;
836:                }
837:
838:                reportResult(localSerializer, tagname, message, target, result,
839:                        action);
840:            }
841:
842:            private void reportResult(String localSerializer, String tagname,
843:                    String message, String target, String result, String action)
844:                    throws SAXException {
845:                sendStartElementEvent(RESULT_ELEMENT);
846:                sendStartElementEvent(EXECUTION_ELEMENT);
847:                sendTextEvent(result);
848:                sendEndElementEvent(EXECUTION_ELEMENT);
849:                sendStartElementEvent(MESSAGE_ELEMENT);
850:                sendTextEvent(message);
851:                sendEndElementEvent(MESSAGE_ELEMENT);
852:                sendStartElementEvent(BEHAVIOUR_ELEMENT);
853:                sendTextEvent(tagname);
854:                sendEndElementEvent(BEHAVIOUR_ELEMENT);
855:                sendStartElementEvent(ACTION_ELEMENT);
856:                sendTextEvent(action);
857:                sendEndElementEvent(ACTION_ELEMENT);
858:                sendStartElementEvent(SOURCE_ELEMENT);
859:                sendTextEvent(target);
860:                sendEndElementEvent(SOURCE_ELEMENT);
861:                if (localSerializer != null) {
862:                    sendStartElementEvent(SERIALIZER_ELEMENT);
863:                    sendTextEvent(localSerializer);
864:                    sendEndElementEvent(SERIALIZER_ELEMENT);
865:                }
866:                sendEndElementEvent(RESULT_ELEMENT);
867:            }
868:
869:            private Document newDocument() throws SAXException,
870:                    ServiceException {
871:                DOMParser parser = (DOMParser) this .manager
872:                        .lookup(DOMParser.ROLE);
873:                try {
874:                    return parser.createDocument();
875:                } finally {
876:                    this .manager.release(parser);
877:                }
878:            }
879:
880:            /* (non-Javadoc)
881:             * @see org.apache.avalon.framework.service.Serviceable#service(ServiceManager)
882:             */
883:            public void service(ServiceManager manager) throws ServiceException {
884:                super .service(manager);
885:                this .xpathProcessor = (XPathProcessor) this .manager
886:                        .lookup(XPathProcessor.ROLE);
887:            }
888:
889:            /* (non-Javadoc)
890:             * @see org.apache.avalon.framework.activity.Disposable#dispose()
891:             */
892:            public void dispose() {
893:                if (this.manager != null) {
894:                    this.manager.release(this.xpathProcessor);
895:                    this.xpathProcessor = null;
896:                }
897:                super.dispose();
898:            }
899:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.