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:
018: package org.apache.lenya.cms.editors.tinymce;
019:
020: import java.io.FileNotFoundException;
021: import java.io.IOException;
022: import java.io.OutputStreamWriter;
023: import java.io.UnsupportedEncodingException;
024: import java.io.Writer;
025:
026: import javax.xml.parsers.ParserConfigurationException;
027:
028: import org.apache.cocoon.components.ContextHelper;
029: import org.apache.cocoon.environment.Request;
030: import org.apache.lenya.cms.cocoon.source.SourceUtil;
031: import org.apache.lenya.cms.linking.LinkConverter;
032: import org.apache.lenya.cms.publication.ResourceType;
033: import org.apache.lenya.cms.usecase.DocumentUsecase;
034: import org.apache.lenya.cms.usecase.UsecaseException;
035: import org.apache.lenya.cms.usecase.xml.UsecaseErrorHandler;
036: import org.apache.lenya.cms.workflow.WorkflowUtil;
037: import org.apache.lenya.cms.workflow.usecases.UsecaseWorkflowHelper;
038: import org.apache.lenya.xml.DocumentHelper;
039: import org.apache.lenya.xml.Schema;
040: import org.apache.lenya.xml.ValidationUtil;
041: import org.w3c.dom.Document;
042: import org.xml.sax.SAXException;
043:
044: /**
045: * TinyMce Usecase
046: *
047: * since there is no really tinymce-specific code in here, most methods should
048: * eventually be moved into DocumentUsecase and shared across all editor usecases.
049: */
050:
051: public class TinyMce extends DocumentUsecase {
052:
053: /**
054: * @see org.apache.lenya.cms.usecase.AbstractUsecase#getNodesToLock()
055: */
056: protected org.apache.lenya.cms.repository.Node[] getNodesToLock()
057: throws UsecaseException {
058: org.apache.lenya.cms.repository.Node[] objects = { getSourceDocument()
059: .getRepositoryNode() };
060: return objects;
061: }
062:
063: /**
064: * @see org.apache.lenya.cms.usecase.AbstractUsecase#initParameters()
065: */
066: protected void initParameters() {
067: super .initParameters();
068:
069: Request request = ContextHelper.getRequest(this .context);
070: setParameter("host", "http://" + request.getServerName() + ":"
071: + request.getServerPort());
072: setParameter("requesturi", request.getRequestURI());
073: }
074:
075: /**
076: * @see org.apache.lenya.cms.usecase.AbstractUsecase#doCheckPreconditions()
077: */
078: protected void doCheckPreconditions() throws Exception {
079: super .doCheckPreconditions();
080: UsecaseWorkflowHelper.checkWorkflow(this .manager, this ,
081: getEvent(), getSourceDocument(), getLogger());
082: }
083:
084: /**
085: * @see org.apache.lenya.cms.usecase.AbstractUsecase#doExecute()
086: */
087: protected void doExecute() throws Exception {
088: super .doExecute();
089:
090: String content = getXmlString(getEncoding());
091:
092: if (getLogger().isDebugEnabled()) {
093: getLogger().debug(content);
094: }
095:
096: saveDocument(getEncoding(), content);
097: }
098:
099: protected String getEncoding() {
100: Request request = ContextHelper.getRequest(this .context);
101: String encoding = request.getCharacterEncoding();
102: return encoding;
103: }
104:
105: protected String getXmlString(String encoding) {
106: // Get namespaces
107: String namespaces = removeRedundantNamespaces(getParameterAsString("tinymce.namespaces"));
108: if (getLogger().isDebugEnabled()) {
109: getLogger().debug(namespaces);
110: }
111: // Aggregate content
112: String content = "<?xml version=\"1.0\" encoding=\"" + encoding
113: + "\"?>\n"
114: + "<html xmlns=\"http://www.w3.org/1999/xhtml\" "
115: + namespaces + ">\n"
116: + " <head><title></title></head>\n" + " <body>\n"
117: + getParameterAsString("tinymce.content")
118: + " </body>\n" + "</html>\n";
119: return content;
120: }
121:
122: public void advance() throws UsecaseException {
123: clearErrorMessages();
124: try {
125: Document xml = getXml();
126: if (xml != null) {
127: validate(xml);
128: }
129: if (!hasErrors()) {
130: SourceUtil.writeDOM(xml, getSourceDocument()
131: .getOutputStream());
132: deleteParameter("content");
133: }
134: } catch (Exception e) {
135: throw new UsecaseException(e);
136: }
137: }
138:
139: protected void doCheckExecutionConditions() throws Exception {
140: super .doCheckExecutionConditions();
141: if (hasErrors()) {
142: return;
143: }
144:
145: Document xml = getXml();
146: if (xml != null) {
147: validate(xml);
148: }
149: }
150:
151: protected void validate(Document xml) throws Exception {
152: ResourceType resourceType = getSourceDocument()
153: .getResourceType();
154: Schema schema = resourceType.getSchema();
155: ValidationUtil.validate(this .manager, xml, schema,
156: new UsecaseErrorHandler(this ));
157: }
158:
159: protected Document getXml() throws ParserConfigurationException,
160: IOException {
161: String encoding = getEncoding();
162: String xmlString = getXmlString(encoding);
163:
164: Document xml = null;
165: try {
166: xml = DocumentHelper.readDocument(xmlString, encoding);
167: } catch (SAXException e) {
168: addErrorMessage("error-document-form", new String[] { e
169: .getMessage() });
170: }
171: return xml;
172: }
173:
174: /**
175: * Save the content to the document source. After saving, the XML is
176: * validated. If validation errors occur, the usecase transaction is rolled
177: * back, so the changes are not persistent. If the validation succeeded, the
178: * workflow event is invoked.
179: * @param encoding The encoding to use.
180: * @param content The content to save.
181: * @throws Exception if an error occurs.
182: */
183: protected void saveDocument(String encoding, String content)
184: throws Exception {
185: org.apache.lenya.cms.publication.Document doc = getSourceDocument();
186: saveXMLFile(encoding, content, doc);
187: LinkConverter converter = new LinkConverter(this .manager,
188: getLogger());
189: converter.convertUrlsToUuids(doc, false);
190:
191: WorkflowUtil.invoke(this .manager, getSession(), getLogger(),
192: doc, getEvent());
193: }
194:
195: /**
196: * Save the XML file
197: * @param encoding The encoding
198: * @param content The content
199: * @param document The source
200: * @throws FileNotFoundException if the file was not found
201: * @throws UnsupportedEncodingException if the encoding is not supported
202: * @throws IOException if an IO error occurs
203: */
204: private void saveXMLFile(String encoding, String content,
205: org.apache.lenya.cms.publication.Document document)
206: throws FileNotFoundException, UnsupportedEncodingException,
207: IOException {
208: Writer writer = null;
209:
210: try {
211: writer = new OutputStreamWriter(document.getOutputStream(),
212: encoding);
213: writer.write(content, 0, content.length());
214: } catch (FileNotFoundException e) {
215: getLogger().error("File not found " + e.toString());
216: } catch (UnsupportedEncodingException e) {
217: getLogger().error("Encoding not supported " + e.toString());
218: } catch (IOException e) {
219: getLogger().error("IO error " + e.toString());
220: } finally {
221: // close all streams
222: if (writer != null)
223: writer.close();
224: }
225: }
226:
227: /**
228: * Remove redundant namespaces
229: * @param namespaces The namespaces to remove
230: * @return The namespace string without the removed namespaces
231: */
232: private String removeRedundantNamespaces(String namespaces) {
233: String[] namespace = namespaces.split(" ");
234:
235: String ns = "";
236: for (int i = 0; i < namespace.length; i++) {
237: if (ns.indexOf(namespace[i]) < 0) {
238: ns = ns + " " + namespace[i];
239: } else {
240: if (getLogger().isDebugEnabled()) {
241: getLogger().debug(
242: "Redundant namespace: " + namespace[i]);
243: }
244: }
245: }
246: return ns;
247: }
248:
249: /**
250: * Add namespaces
251: * @param namespaces The namespaces to add
252: * @param content The content to add them to
253: * @return The content with the added namespaces
254: */
255: /* private String addNamespaces(String namespaces, String content) {
256: int i = content.indexOf(">");
257: return content.substring(0, i) + " " + namespaces + content.substring(i);
258: }
259: */
260:
261: protected String getEvent() {
262: return "edit";
263: }
264:
265: }
|