001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.xsl.transform;
043:
044: import java.io.IOException;
045: import java.io.PrintWriter;
046: import java.net.MalformedURLException;
047: import java.net.URL;
048: import java.net.UnknownHostException;
049: import java.util.Iterator;
050: import java.util.List;
051: import java.util.Vector;
052: import javax.servlet.ServletConfig;
053: import javax.servlet.ServletException;
054: import javax.servlet.http.HttpServlet;
055: import javax.servlet.http.HttpServletRequest;
056: import javax.servlet.http.HttpServletResponse;
057: import javax.xml.transform.Result;
058: import javax.xml.transform.Source;
059: import javax.xml.transform.TransformerException;
060: import javax.xml.transform.stream.StreamResult;
061: import org.netbeans.api.xml.cookies.CookieMessage;
062: import org.netbeans.api.xml.cookies.CookieObserver;
063: import org.netbeans.api.xml.cookies.TransformableCookie;
064: import org.netbeans.api.xml.cookies.XMLProcessorDetail;
065: import org.netbeans.modules.xsl.utils.TransformUtil;
066: import org.netbeans.spi.xml.cookies.DefaultXMLProcessorDetail;
067: import org.openide.filesystems.FileObject;
068: import org.openide.filesystems.FileSystem;
069: import org.openide.filesystems.Repository;
070: import org.openide.filesystems.URLMapper;
071: import org.openide.util.NbBundle;
072: import org.xml.sax.SAXParseException;
073:
074: /**
075: *
076: * @author Libor Kramolis
077: */
078: public class TransformServlet extends HttpServlet {
079: private static final long serialVersionUID = 1632869007241230624L;
080:
081: private static TransformableCookie transformable;
082: /** Last cached XML Source. */
083: private static Source xmlSource;
084: /** Last cached XSL Script. */
085: private static Source xslSource;
086:
087: public static void prepare(TransformableCookie trans, Source xml,
088: Source xsl) {
089: transformable = trans;
090: xmlSource = xml;
091: xslSource = xsl;
092: }
093:
094: /** Initializes the servlet.
095: */
096: public void init(ServletConfig config) throws ServletException {
097: super .init(config);
098: }
099:
100: /** Destroys the servlet.
101: */
102: public void destroy() {
103: xmlSource = null;
104: xslSource = null;
105: }
106:
107: /** Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
108: * @param request servlet request
109: * @param response servlet response
110: */
111: protected void processRequest(HttpServletRequest request,
112: HttpServletResponse response) throws ServletException,
113: IOException {
114: PrintWriter out = response.getWriter();
115: Result outputResult = new StreamResult(out);
116:
117: Observer notifier = new Observer();
118: try {
119: String guessOutputExt = TransformUtil
120: .guessOutputExt(xslSource);
121: String mimeType;
122: if (guessOutputExt.equals("txt")) { // NOI18N
123: mimeType = "text/plain"; // NOI18N
124: } else if (guessOutputExt.equals("xml")) { // NOI18N
125: mimeType = "text/xml"; // NOI18N
126: } else if (guessOutputExt.equals("html")) { // NOI18N
127: mimeType = "text/html"; // NOI18N
128: } else {
129: mimeType = null;
130: }
131:
132: if (mimeType != null) {
133: response.setContentType(mimeType);
134: }
135:
136: // if ( Util.THIS.isLoggable() ) /* then */ {
137: // Util.THIS.debug ("[TransformServlet] Response MIME Type: '" + mimeType + "'");
138: // Util.THIS.debug (" xmlSource.getSystemId() = " + xmlSource.getSystemId());
139: // Util.THIS.debug (" transformable = " + transformable);
140: // Util.THIS.debug (" xslSource.getSystemId() = " + xslSource.getSystemId());
141: // }
142:
143: TransformUtil.transform(xmlSource, transformable,
144: xslSource, outputResult, notifier);
145: } catch (Exception exc) {
146: // if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug (" EXCEPTION!!!: " + exc.getClass().getName(), exc);
147:
148: // thrown if error in style sheet
149: CookieMessage message = null;
150:
151: if (exc instanceof TransformerException) {
152: // do not log again TransformerException, it is already done by ErrorListener
153: } else if (exc instanceof SAXParseException) {
154: message = new CookieMessage(TransformUtil
155: .unwrapException(exc).getLocalizedMessage(),
156: CookieMessage.FATAL_ERROR_LEVEL,
157: new DefaultXMLProcessorDetail(
158: (SAXParseException) exc));
159: } else {
160: message = new CookieMessage(exc.getLocalizedMessage(),
161: CookieMessage.FATAL_ERROR_LEVEL);
162: }
163:
164: // if ( Util.THIS.isLoggable() ) /* then */ {
165: // Util.THIS.debug (" message = " + message);
166: // Util.THIS.debug (" notifier = " + notifier);
167: // }
168:
169: if (message != null) {
170: notifier.receive(message);
171: }
172:
173: // create warning page
174: response.setContentType("text/html");
175:
176: out.println("<html><head>");
177: out.println(" <title>"
178: + NbBundle.getMessage(TransformServlet.class,
179: "MSG_error_html_title") + "</title>");
180: out.println(" <style>"
181: + NbBundle.getMessage(TransformServlet.class,
182: "MSG_error_html_style") + "</style>");
183: out.println("</head><body>");
184: out.println(" <h2>"
185: + NbBundle.getMessage(TransformServlet.class,
186: "MSG_error_page_title") + "</h2>");
187: out.println(" <p>"
188: + NbBundle.getMessage(TransformServlet.class,
189: "MSG_error_page_message") + "</p>");
190: out.println(" <hr size=\"1\" noshade=\"\" />\n"
191: + generateReport(notifier.getList())
192: + "<hr size=\"1\" noshade=\"\" />");
193: out.println(" <p>"
194: + NbBundle.getMessage(TransformServlet.class,
195: "MSG_error_bottom_message") + "</p>");
196: out.println("</body></html>");
197: } finally {
198: out.close();
199: }
200: }
201:
202: /** Handles the HTTP <code>GET</code> method.
203: * @param request servlet request
204: * @param response servlet response
205: */
206: protected void doGet(HttpServletRequest request,
207: HttpServletResponse response) throws ServletException,
208: IOException {
209: processRequest(request, response);
210: }
211:
212: /** Handles the HTTP <code>POST</code> method.
213: * @param request servlet request
214: * @param response servlet response
215: */
216: protected void doPost(HttpServletRequest request,
217: HttpServletResponse response) throws ServletException,
218: IOException {
219: processRequest(request, response);
220: }
221:
222: /** Returns a short description of the servlet.
223: */
224: public String getServletInfo() {
225: return "XSL Transformation Preview Servlet";
226: }
227:
228: public static URL getServletURL() throws MalformedURLException,
229: UnknownHostException {
230:
231: URL base = getSampleHTTPServerURL();
232: // XXX hack: assume that the path /servlet/CLASSNAME works on this server.
233: URL root = new URL(base.getProtocol(), base.getHost(), base
234: .getPort(), "/servlet/"
235: + TransformServlet.class.getName() + "/");
236:
237: return root;
238: }
239:
240: private static URL getSampleHTTPServerURL() {
241: FileSystem fs = Repository.getDefault().getDefaultFileSystem();
242: FileObject fo = fs.findResource("HTTPServer_DUMMY");
243: if (fo == null) {
244: return null;
245: }
246: URL u = URLMapper.findURL(fo, URLMapper.NETWORK);
247: return u;
248: }
249:
250: private String generateReport(List msgList) {
251: StringBuffer sb = new StringBuffer();
252:
253: try {
254:
255: Iterator it = msgList.iterator();
256: while (it.hasNext()) {
257: CookieMessage msg = (CookieMessage) it.next();
258: XMLProcessorDetail detail = (XMLProcessorDetail) msg
259: .getDetail(XMLProcessorDetail.class);
260:
261: // Message
262: sb.append(" <font class=\"")
263: .append(levelName(msg.getLevel()))
264: .append("\">").append(msg.getMessage()).append(
265: "</font>"); // NOI18N
266:
267: if (detail != null) {
268: // SystemId
269: String systemId = preferFileName(detail
270: .getSystemId());
271: if (systemId != null) {
272: sb.append(" (<font class=\"system-id\">");
273: boolean isFile = systemId.startsWith("file:");
274: if (isFile) {
275: sb.append("<a href=\"").append(systemId)
276: .append("\">");
277: }
278: sb.append(systemId);
279: if (isFile) {
280: sb.append("</a>");
281: }
282: sb.append("</font>\n"); // NOI18N
283: // LineNumber
284: sb
285: .append(
286: " [<font class=\"line-number\">")
287: .append(detail.getLineNumber()).append(
288: "</font>])<br>"); // NOI18N
289: }
290: }
291: }
292:
293: } catch (Exception exc) {
294: //if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug (exc);
295: }
296:
297: return sb.toString();
298: }
299:
300: private String preferFileName(String systemId) {
301: String name = systemId;
302:
303: try {
304: URL url = new URL(systemId);
305: FileObject fo = URLMapper.findFileObject(url);
306: if (fo != null) {
307: name = TransformUtil.getURLName(fo);
308: }
309: } catch (Exception exc) {
310: // ignore it -> use systemId
311:
312: //if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug (exc);
313: }
314:
315: return name;
316: }
317:
318: private String levelName(int level) {
319: if (level == CookieMessage.FATAL_ERROR_LEVEL) {
320: return "fatal-error"; // NOI18N
321: } else if (level == CookieMessage.ERROR_LEVEL) {
322: return "error"; // NOI18N
323: } else if (level == CookieMessage.WARNING_LEVEL) {
324: return "warning"; // NOI18N
325: } else { // CookieMessage.INFORMATIONAL_LEVEL
326: return "informational"; // NOI18N
327: }
328: }
329:
330: //
331: // class Observer
332: //
333:
334: private static class Observer implements CookieObserver {
335:
336: private final List msgList;
337:
338: public Observer() {
339: msgList = new Vector();
340: }
341:
342: public void receive(CookieMessage msg) {
343: msgList.add(msg);
344: }
345:
346: public List getList() {
347: return msgList;
348: }
349: }
350: }
|