incubator-sling-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From fmesc...@apache.org
Subject svn commit: r585096 - in /incubator/sling/whiteboard/microsling/src/main: java/org/apache/sling/microsling/etc/EspReader.java java/org/apache/sling/microsling/slingservlets/RhinoJavascriptServlet.java webapp/server-side-javascript.html
Date Tue, 16 Oct 2007 10:18:14 GMT
Author: fmeschbe
Date: Tue Oct 16 03:18:07 2007
New Revision: 585096

URL: http://svn.apache.org/viewvc?rev=585096&view=rev
Log:
SLING-57 Resource: retarget the data to be the mapped object and add Item for the addressed
repository Item
SLING-58 Add support for templated JavaScript

Added:
    incubator/sling/whiteboard/microsling/src/main/java/org/apache/sling/microsling/etc/EspReader.java
Modified:
    incubator/sling/whiteboard/microsling/src/main/java/org/apache/sling/microsling/slingservlets/RhinoJavascriptServlet.java
    incubator/sling/whiteboard/microsling/src/main/webapp/server-side-javascript.html

Added: incubator/sling/whiteboard/microsling/src/main/java/org/apache/sling/microsling/etc/EspReader.java
URL: http://svn.apache.org/viewvc/incubator/sling/whiteboard/microsling/src/main/java/org/apache/sling/microsling/etc/EspReader.java?rev=585096&view=auto
==============================================================================
--- incubator/sling/whiteboard/microsling/src/main/java/org/apache/sling/microsling/etc/EspReader.java
(added)
+++ incubator/sling/whiteboard/microsling/src/main/java/org/apache/sling/microsling/etc/EspReader.java
Tue Oct 16 03:18:07 2007
@@ -0,0 +1,721 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.microsling.etc;
+
+import java.io.FilterReader;
+import java.io.IOException;
+import java.io.PushbackReader;
+import java.io.Reader;
+import java.util.Stack;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The <code>EspReader</code> is a <code>FilterReader</code> which
takes
+ * JSP like input and produces plain ECMA script output. The filtering
+ * modifications done on the input comprise the following :
+ * <ul>
+ * <li>Template text (HTML) is wrapped by out.write(). At most one line of
+ * text is wrapped into a single write() call. Double quote characters in the
+ * template text (e.g. for HTML tag attribute values) are escaped.
+ * <li>ECMA code is written to the output as is.
+ * <li>ECMA slash star (/*) comments are also written as is.
+ * <li>ECMA slash slash (//) comments are written as is.
+ * <li>JSP style template comments (<%-- -->) are also removed from the
+ * stream. Lineendings (LFs and CRLFs) are written, though.
+ * <li>HTML comments (<!-- -->) are not treated specially. Rather they are
+ * handled as plain template text written to the output wrapped in
+ * out.write(). The consequence of this behavious is, that as in JSP ECMA
+ * expressions may be included within the comments.
+ * </ul>
+ * <p>
+ * The nice thing about this reader is, that the line numbers of the resulting
+ * stream match the line numbers of the matching contents of the input stream.
+ * Due to the insertion of write() calls, column numbers will not necessarily
+ * match, though. This is especially true if you mix ECMA code tags (<% %>)
+ * with template text on the same line.
+ * <p>
+ * For maximum performance it is advisable to not create the EspReader with a
+ * plain FileReader or InputStreamReader but rather with a BufferedReader based
+ * on one of the simpler Readers. The reasons for this is, that we call the base
+ * reader character by character. This in turn is not too performing if the base
+ * reader does not buffer its input.
+ */
+public class EspReader extends FilterReader {
+
+    /** default log */
+    private final Logger log = LoggerFactory.getLogger(EspReader.class);
+
+    /**
+     * Default parser state. This is the state the parser starts running in. In
+     * this state all text is treated as template text, which should be wrapped
+     * by out.write() line by line.
+     */
+    private static final byte PARSE_STATE_ESP = 1;
+
+    /**
+     * ECMA script reading state. When in this state everything upto to the next
+     * <code>%&gt;</code> is written to the output verbatim with three
+     * exceptions : ECMA slash star comments are handed over to handled by the
+     * {@link #PARSE_STATE_ECMA_COMMENT} state, quoted strings are handled in
+     * the {@link #PARSE_STATE_QUOTE} state and ECMA slash slash comments are
+     * handled in {@link #PARSE_STATE_ECMA_COMMENTL} state.
+     */
+    private static final byte PARSE_STATE_ECMA = 3;
+
+    /**
+     * ECMA script expression reading state. This state works exactly the same
+     * as the {@link #PARSE_STATE_ECMA} state with one exception: The whole
+     * code enclosed in the <code>&lt;%=</code> ... <code>%&gt;</code>
tags
+     * is itself wrapped with a <code>out.write()</code> statement
+     * verbatim.
+     */
+    private static final byte PARSE_STATE_ECMA_EXPR = 4;
+
+    /**
+     * JSP comment reading state. When in this state everything upto the closing
+     * <code>--&gt;</code> tag is removed from the stream.
+     */
+    private static final byte PARSE_STATE_JSP_COMMENT = 5;
+
+    /**
+     * ECMA quoted string reading state. When in this state everything is
+     * written exactly as in the input stream upto the closing quote, which
+     * matches the opening quote.
+     */
+    private static final byte PARSE_STATE_QUOTE = 6;
+
+    /**
+     * Verbatim copy state. When in this state as many as verbatimChars
+     * characters are returned unchecked. As soon as this number of characters
+     * is returned, the last state is popped from the stack. This state is
+     * mainly used to (re-)inject static text into the output without further
+     * processing.
+     */
+    private static final byte PARSE_STATE_VERBATIM = 8;
+
+    /**
+     * ECMA Comment reading state. When in this state, an ECMA slash star
+     * comment is read (and completely returned).
+     */
+    private static final byte PARSE_STATE_ECMA_COMMENT = 9;
+
+    /**
+     * ECMA Comment reading state. When in this state, an ECMA slash slash
+     * comment is read (and completely returned).
+     */
+    private static final byte PARSE_STATE_ECMA_COMMENTL = 10;
+
+    /**
+     * To work with lookahead and character insertion, we use a PushbackReader.
+     */
+    private PushbackReader input;
+
+    /**
+     * Current parse state. This field contains one of the
+     * <code>PARSE_STATE</code> constants.
+     */
+    private byte state;
+
+    /**
+     * Stack of states. Whenever we enter a new state, the old state is pushed
+     * onto the stack. When a state is left, the previous one is popped from the
+     * stack.
+     *
+     * @see #pushState(byte)
+     * @see #popState()
+     * @see #state
+     */
+    private Stack<Byte> stateStack;
+
+    /**
+     * This value is set to true, if the parser is expected to insert a
+     * out.write() call into the input stream when in state
+     * {@link #PARSE_STATE_ESP}. When this field is true, it is not
+     * necessairily the case, that we are at the start of a real text line.
+     */
+    private boolean lineStart;
+
+    /**
+     * If characters are put into the pushback Stream that should be given back
+     * verbatim, this value is set to the number of such consecutive characters.
+     */
+    private int verbatimChars;
+
+    /**
+     * During String matching this is the character used for string quoting.
+     */
+    private char quoteChar;
+
+    /**
+     * Set to true if an escape character (\) has been encountered within a
+     * quoted string.
+     */
+    private boolean escape;
+
+    /**
+     * Create an EspReader on top of the given <code>baseReader</code>. The
+     * constructor wraps the input reader with a <code>PushbackReader</code>,
+     * so that input stream modifications may be handled transparently by our
+     * {@link #doRead()} method.
+     */
+    public EspReader(Reader baseReader) {
+        super(baseReader);
+        this.input = new PushbackReader(baseReader, 100);
+        this.stateStack = new Stack<Byte>();
+        this.lineStart = true;
+        this.verbatimChars = -1;
+        this.quoteChar = 0;
+        this.escape = false;
+
+        // Start in ESP (template text) state
+        pushState(PARSE_STATE_ESP);
+    }
+
+    /**
+     * Check whether we may block at the next read() operation. We may be ready
+     * if and only if our input reader is ready. But this does not guarantee
+     * that we won't block, as due to filtering there may be more than one
+     * character needed from the input to return one.
+     *
+     * @return <code>true</code> if a character is available on the
+     *         <code>PushbackReader</code>.
+     * @throws IOException if the reader is not open
+     */
+    public boolean ready() throws IOException {
+        ensureOpen();
+        return input.ready();
+    }
+
+    /**
+     * Return the next filtered character. This need not be the next character
+     * of the input stream. It may be a character from the input reader, after
+     * having skipped filtered characters or it may be a character injected due
+     * to translation of template text to ECMA code.
+     *
+     * @return the next character after filtering or -1 at the end of the input
+     *         reader
+     * @throws IOException if the reader is not open
+     */
+    public int read() throws IOException {
+        ensureOpen();
+        return doRead();
+    }
+
+    /**
+     * Fill the given buffer with filtered or injected characters. This need not
+     * be the next characters of the input stream. It may be characters from the
+     * input reader, after having skipped filtered characters or it may be a
+     * characters injected due to translation of template text to ECMA code.
+     * This method is exactly the same as
+     * <code>read(cbuf, 0, cbuf.length)</code>.
+     *
+     * @param cbuf The character buffer to fill with (filtered) characters
+     * @return the number of characters filled in the buffer or -1 at the end of
+     *         the input reader.
+     * @throws IOException if the reader is not open
+     */
+    public int read(char[] cbuf) throws IOException {
+        return read(cbuf, 0, cbuf.length);
+    }
+
+    /**
+     * Fill the buffer from the offset with the number of characters given. This
+     * need not be the next characters of the input stream. It may be characters
+     * from the input reader, after having skipped filtered characters or it may
+     * be a characters injected due to translation of template text to ECMA
+     * code.
+     *
+     * @param cbuf The character buffer to fill with (filtered) characters
+     * @param off Offset from where to start in the buffer
+     * @param len The number of characters to fill into the buffer
+     * @return the number of characters filled in the buffer or -1 at the end of
+     *         the input reader.
+     * @throws IOException if the reader is not open
+     * @throws IndexOutOfBoundsException if len is negative, off is negative or
+     *             higher than the buffer length or off+len is negative or
+     *             beyond the buffer size.
+     */
+    public int read(char[] cbuf, int off, int len) throws java.io.IOException {
+        ensureOpen();
+
+        // Check lines (taken from InputStreamReader ;-)
+        if ((off < 0) || (off > cbuf.length) || (len < 0)
+            || ((off + len) > cbuf.length) || ((off + len) < 0)) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return 0;
+        }
+
+        int i;
+        int c;
+        for (i = off; i < len; i++) {
+            if ((c = doRead()) < 0) {
+                break;
+            }
+            cbuf[i] = (char) c;
+        }
+
+        return (i == off) ? -1 : i - off;
+    }
+
+    /**
+     * Skip the number of filtered characters. The skip method is the same as
+     * calling read() repeatedly for the given number of characters and throwing
+     * away the result. If the end of input reader is reached before having
+     * skipped the number of characters, the method returns the number
+     * characters skipped so far.
+     *
+     * @param n the number of (filtered) characters to skip
+     * @return the number of (filtered) characters actually skipped
+     * @throws IllegalArgumentException if n is negative
+     * @throws IOException if the reading the characters throws
+     */
+    public long skip(long n) throws IOException {
+        if (n < 0L) {
+            throw new IllegalArgumentException("skip value is negative");
+        }
+
+        long i = -1;
+        while (++i < n) {
+            if (doRead() < 0) {
+                break;
+            }
+        }
+        return i;
+    }
+
+    /**
+     * Close the EspReader.
+     */
+    public void close() throws java.io.IOException {
+        if (input != null) {
+            input.close();
+            input = null;
+        }
+
+        // I dont' know what happens ??
+        super.close();
+    }
+
+    /**
+     * Mark the present position in the stream. The <code>mark</code> for
+     * class <code>EspReader</code> always throws an throwable.
+     *
+     * @param readAheadLimit The number of characters to read ahead
+     * @exception IOException Always, since mark is not supported
+     */
+    public void mark(int readAheadLimit) throws IOException {
+        throw new IOException("mark() not supported");
+    }
+
+    /**
+     * Tell whether this stream supports the mark() operation, which it does
+     * not.
+     *
+     * @return false Always, since mark is not supported
+     */
+    public boolean markSupported() {
+        return false;
+    }
+
+    /**
+     * Reset the stream. The <code>reset</code> method of
+     * <code>EspReader</code> always throws an throwable.
+     *
+     * @exception IOException Always, since reset is not supported
+     */
+    public void reset() throws IOException {
+        throw new IOException("reset() not supported");
+    }
+
+    /**
+     * Internal routine doing all the footwork of reading one character at a
+     * time from the <code>PushbackReader</code> and acting according to the
+     * current state.
+     * <p>
+     * This filter is implemented using a finite state machine using the states
+     * defined above with the <code>PARSE_STATE</code> constants. Each state
+     * may do a look ahead in certain situations to decide on further steps.
+     * Characters looked ahead may or may not be inserted back into the input
+     * stream depending on the concrete state.
+     *
+     * @return the next character from the input stream according to the current
+     *         state or -1 to indicate end of file.
+     * @throws IOException if the input <code>PushbackReader</code> throws it
+     */
+    private int doRead() throws IOException {
+
+        // we return out of the loop, if we find a character passing the filter
+        for (;;) {
+
+            // Get a character from the input, which may well have been
+            // injected using the unread() method
+            int c = input.read();
+
+            // catch EOF
+            if (c < 0) {
+
+                // if a template text line is still incomplete, inject
+                // proper line ending and continue until this has been returned
+                if (!lineStart && state == PARSE_STATE_ESP) {
+                    doVerbatim("\");"); // line ending injection
+                    lineStart = true; // mark the line having ended
+                    continue; // let's start read the injection
+                }
+
+                return c; // return the marker, we're done
+            }
+
+            // Do the finite state machine
+            switch (state) {
+
+                // NOTE :
+                // - continue means ignore current character, read next
+                // - break means return current character
+
+                // Template text state - text is wrapped in out.write()
+                case PARSE_STATE_ESP:
+
+                    // might start ECMA code/expr, ESP comment or JSP comment
+                    if (c == '<') {
+                        int c2 = input.read();
+                        int c3 = input.read();
+
+                        if (c2 == '%') {
+
+                            // ECMA or JSP comment
+
+                            if (c3 == '=') {
+
+                                // ECMA expression <%= ... %>
+                                pushState(PARSE_STATE_ECMA_EXPR);
+                                doVerbatim("out.write(");
+                                if (!lineStart) {
+                                    doVerbatim("\");");
+                                }
+                                continue;
+
+                            } else if (c3 == '-') {
+
+                                // (Possible) JSP Comment <%-- ... --%>
+                                int c4 = input.read();
+                                if (c4 == '-') {
+                                    pushState(PARSE_STATE_JSP_COMMENT);
+                                    continue;
+                                }
+                                input.unread(c4);
+
+                            }
+
+                            // We only get here if we are sure about ECMA
+
+                            // ECMA code <% ... %>
+                            input.unread(c3);
+                            pushState(PARSE_STATE_ECMA);
+                            if (!lineStart) {
+                                doVerbatim("\");");
+                            }
+                            continue;
+
+                        }
+
+                        // Nothing special, push back read ahead
+                        input.unread(c3);
+                        input.unread(c2);
+
+                        // End of template text line
+                    } else if (c == '\r' || c == '\n') {
+                        String lineEnd; // will be injected
+
+                        // Check for real CRLF
+                        if (c == '\r') {
+                            int c2 = input.read();
+                            if (c2 != '\n') {
+                                input.unread(c2);
+                                lineEnd = "\\r";
+                            } else {
+                                lineEnd = "\\r\\n";
+                            }
+                        } else {
+                            lineEnd = "\\n";
+                        }
+
+                        // Only write line ending if not empty
+                        if (!lineStart) {
+                            doVerbatim("\");\n");
+                            doVerbatim(lineEnd);
+                            lineStart = true;
+
+                        } else { // if (lineEnd.length() > 1) {
+                            // no matter what line ending we have, make it LF
+                            doVerbatim("\");\n");
+                            doVerbatim(lineEnd);
+                            doVerbatim("out.write(\"");
+                        }
+
+                        continue;
+
+                        // template text is wrapped with double quotes, which
+                        // when occurring in the text must be escaped.
+                        // We also escape the escape character..
+                    } else if (c == '"' || c == '\\') {
+
+                        doVerbatim(String.valueOf((char) c));
+                        c = '\\';
+
+                    }
+
+                    // If in template text at the beginning of a line
+                    if (lineStart) {
+                        lineStart = false;
+                        doVerbatim("out.write(\"" + (char) c);
+                        continue;
+                    }
+
+                    break;
+
+                // Reading ECMA code or and ECMA expression
+                case PARSE_STATE_ECMA_EXPR:
+                case PARSE_STATE_ECMA:
+
+                    if (c == '%') {
+
+                        // might return to PARSE_STATE_ESP
+                        int c2 = input.read();
+                        if (c2 == '>') {
+
+                            // An expression is wrapped in out.write()
+                            if (popState() == PARSE_STATE_ECMA_EXPR) {
+                                doVerbatim(");");
+                            }
+
+                            // next ESP needs out.write(
+                            lineStart = true;
+
+                            continue;
+
+                        }
+
+                        // false alert, push back
+                        input.unread(c2);
+
+                    } else if (c == '/') {
+
+                        // might be ECMA Comment
+                        int c2 = input.read();
+                        if (c2 == '/') {
+                            // single line comment
+                            pushState(PARSE_STATE_ECMA_COMMENTL);
+                        } else if (c2 == '*') {
+                            // multiline comment
+                            pushState(PARSE_STATE_ECMA_COMMENT);
+                        }
+
+                        // false alert, push back
+                        input.unread(c2);
+
+                    } else if (c == '\'' || c == '"') {
+
+                        // an ECMA string
+                        escape = false; // start unescaped
+                        quoteChar = (char) c; // to recognize the end
+                        pushState(PARSE_STATE_QUOTE);
+
+                    }
+                    break;
+
+                // Reading a JSP comment, only returning line endings
+                case PARSE_STATE_JSP_COMMENT:
+
+                    // JSP comments end complexly with --%>
+                    if (c == '-') {
+                        int c2 = input.read();
+                        if (c2 == '-') {
+                            int c3 = input.read();
+                            if (c3 == '%') {
+                                int c4 = input.read();
+                                if (c4 == '>') {
+
+                                    // we really reached the end ...
+                                    popState();
+                                    continue;
+
+                                }
+                                input.unread(c4);
+                            }
+                            input.unread(c3);
+                        }
+                        input.unread(c2);
+
+                        // well, not definitely correct but reasonably accurate
+                        // ;-)
+                    } else if (c == '\r' || c == '\n') {
+
+                        // terminate an open template line
+                        if (!lineStart) {
+                            input.unread(c); // push back the character
+                            doVerbatim("\");"); // insert ");
+                            lineStart = true; // mark the line start
+                            continue; // Force read of the "
+                        }
+
+                        break;
+                    }
+
+                    // continue reading another character in the comment
+                    continue;
+
+                    // Read an ECMA string upto the ending quote character
+                case PARSE_STATE_QUOTE:
+
+                    // if unescaped quote character
+                    if (c == quoteChar && !escape) {
+                        popState();
+                    } else {
+                        // mark escape - only if not already escaped (bug 7079)
+                        escape = c == '\\' && !escape;
+                    }
+
+                    break;
+
+                // Return characters unfiltered
+                case PARSE_STATE_VERBATIM:
+
+                    // Go back to previous state if all characters read
+                    if (--verbatimChars < 0) {
+                        popState();
+                    }
+
+                    break;
+
+                // Return an ECMA multiline comment, ending with */
+                case PARSE_STATE_ECMA_COMMENT:
+
+                    // Might be the end of the comment
+                    if (c == '*') {
+                        int c2 = input.read();
+                        if (c2 == '/') {
+                            popState(); // back to previous
+                            doVerbatim("/"); // return slash verbatim
+                        } else {
+                            input.unread(c2);
+                        }
+                    }
+
+                    break;
+
+                // Return an ECMA single line comment, ending with end of line
+                case PARSE_STATE_ECMA_COMMENTL:
+
+                    // CRLF recognition
+                    if (c == '\r') {
+                        int c2 = input.read();
+                        if (c2 == '\n') {
+                            popState();
+                        }
+                        input.unread(c2);
+
+                        // LF only line end
+                    } else if (c == '\n') {
+                        popState();
+                    }
+
+                    break;
+
+                // What ???!!!
+                default:
+
+                    // we warn and go back to default state
+                    log.warn("doRead(): unknown state " + state);
+                    state = PARSE_STATE_ESP;
+
+                    break;
+
+            } // switch
+
+            // Exiting the switch normally we return the current character
+            return c;
+
+        } // for(;;)
+
+    }
+
+    /**
+     * Throw an IOException if the reader is not open
+     *
+     * @throws IOException if the reader is (already) closed
+     */
+    private void ensureOpen() throws IOException {
+        if (input == null) {
+            throw new IOException("Reader is closed");
+        }
+    }
+
+    /**
+     * Injects a string into the input stream, sets the number of characters to
+     * return verbatim and change state. The state change only happens if we are
+     * not in verbatim state already. Else the current string is simply
+     * prepended to the previous inhjection. This is simply a convenience method
+     * ;-)
+     *
+     * @param verbatimString The string to inject into the input stream
+     * @throws IOException if the 'unreading' throws
+     */
+    private void doVerbatim(String verbatimString) throws IOException {
+
+        // Push 'back' into PushbackReader
+        input.unread(verbatimString.toCharArray());
+
+        // Set the number of characters to return verbatim
+        verbatimChars += verbatimString.length();
+
+        // Change state if not already in verbatim state
+        if (state != PARSE_STATE_VERBATIM) {
+            pushState(PARSE_STATE_VERBATIM);
+        }
+    }
+
+    /**
+     * Push the current state on stack and set to <code>newState</code>. This
+     * new state is also returned.
+     *
+     * @param newState the new state to set
+     * @return the new state set according to <code>newState</code>
+     */
+    private byte pushState(byte newState) {
+        stateStack.push(state);
+        return state = newState;
+    }
+
+    /**
+     * Sets the current state to the state stored at the top of the stack. If
+     * the stack is empty prior to this call, the default template text state is
+     * set. The method returns the state prior to setting to the new state.
+     *
+     * @return the state prior to calling this method
+     */
+    private byte popState() {
+        byte oldState = state;
+        state = stateStack.isEmpty() ? PARSE_STATE_ESP : stateStack.pop();
+        return oldState;
+    }
+
+}
\ No newline at end of file

Modified: incubator/sling/whiteboard/microsling/src/main/java/org/apache/sling/microsling/slingservlets/RhinoJavascriptServlet.java
URL: http://svn.apache.org/viewvc/incubator/sling/whiteboard/microsling/src/main/java/org/apache/sling/microsling/slingservlets/RhinoJavascriptServlet.java?rev=585096&r1=585095&r2=585096&view=diff
==============================================================================
--- incubator/sling/whiteboard/microsling/src/main/java/org/apache/sling/microsling/slingservlets/RhinoJavascriptServlet.java
(original)
+++ incubator/sling/whiteboard/microsling/src/main/java/org/apache/sling/microsling/slingservlets/RhinoJavascriptServlet.java
Tue Oct 16 03:18:07 2007
@@ -16,106 +16,141 @@
  */
 package org.apache.sling.microsling.slingservlets;
 
+import java.io.BufferedReader;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.io.Reader;
 
 import javax.jcr.Node;
+import javax.jcr.RepositoryException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.sling.microsling.etc.AbstractSlingServlet;
+import org.apache.sling.microsling.etc.EspReader;
 import org.apache.sling.microsling.requestcontext.SlingRequestContext;
 import org.apache.sling.microsling.scripting.FileNodeRequestAttribute;
 import org.apache.sling.microsling.scripting.SlingScriptResolver;
 import org.mozilla.javascript.Context;
 import org.mozilla.javascript.ScriptableObject;
 
-/** A SlingServlet that uses the Rhino interpreter to process
- *  Sling request with server-side javascript.
+/**
+ * A SlingServlet that uses the Rhino interpreter to process Sling request with
+ * server-side javascript.
  */
 public class RhinoJavascriptServlet extends AbstractSlingServlet {
 
     final SlingScriptResolver scriptResolver = new SlingScriptResolver();
+
     public final static String JS_SCRIPT_EXTENSION = "js";
-        
+
+    public final static String ESP_SCRIPT_EXTENSION = "esp";
+
     /** True if we have a js script to handle the current request */
     public boolean canProcess(HttpServletRequest req) throws Exception {
         boolean result = false;
 
-        final Node script = scriptResolver.resolveScript(req,JS_SCRIPT_EXTENSION);
-        if(script!=null) {
-            new FileNodeRequestAttribute(script,req);
+        final Node jsScript = scriptResolver.resolveScript(req,
+            JS_SCRIPT_EXTENSION);
+        if (jsScript != null) {
+            new FileNodeRequestAttribute(jsScript, req);
             result = true;
+        } else {
+            final Node espScript = scriptResolver.resolveScript(req,
+                ESP_SCRIPT_EXTENSION);
+            if (espScript != null) {
+                new FileNodeRequestAttribute(espScript, req) {
+                    @Override
+                    public Reader getReader() throws RepositoryException {
+                        return new EspReader(new BufferedReader(
+                            super.getReader()));
+                    }
+                };
+
+                result = true;
+            }
+
         }
-        
+
         return result;
     }
-    
+
     /** Called by the doX methods to handle HTTP request method X */
-    protected void processRequest(HttpServletRequest req, HttpServletResponse resp) throws
Exception {
+    protected void processRequest(HttpServletRequest req,
+            HttpServletResponse resp) throws Exception {
         final SlingRequestContext ctx = SlingRequestContext.getFromRequest(req);
-        
+
         // get the script that was revolved by canProcess
         final FileNodeRequestAttribute script = FileNodeRequestAttribute.getFromRequest(req);
-        final Reader scriptReader = script.getReader(); 
+        final Reader scriptReader = script.getReader();
 
         // create a rhino Context and execute the script
         try {
             final Context rhinoContext = Context.enter();
-            
+
             // put useful values in scope for the JS script
             final ScriptableObject scope = rhinoContext.initStandardObjects();
-            final Object wrappedResource = Context.javaToJS(ctx.getResource(),scope);
+            final Object wrappedResource = Context.javaToJS(ctx.getResource(),
+                scope);
             ScriptableObject.putProperty(scope, "resource", wrappedResource);
-            
+
             // set the output content type
             final String fakeFilename = "fake." + ctx.getExtension();
-            resp.setContentType(ctx.getMimeType(fakeFilename) + "; charset=utf-8");
-            
+            resp.setContentType(ctx.getMimeType(fakeFilename)
+                + "; charset=utf-8");
+
             // evaluate the script, assuming it writes something to the output
-            final PrintWriter pw = new PrintWriter(new OutputStreamWriter(resp.getOutputStream()));
-            ScriptableObject.putProperty(scope, "out", Context.javaToJS(pw, scope));
-            
+            final PrintWriter pw = new PrintWriter(new OutputStreamWriter(
+                resp.getOutputStream()));
+            ScriptableObject.putProperty(scope, "out", Context.javaToJS(pw,
+                scope));
+
             final String sourceName = script.getNode().getPath();
             final int lineNumber = 1;
             final Object securityDomain = null;
-            rhinoContext.evaluateReader(scope, scriptReader, sourceName, lineNumber, securityDomain);
-            
+            rhinoContext.evaluateReader(scope, scriptReader, sourceName,
+                lineNumber, securityDomain);
+
             pw.flush();
-            
+
         } finally {
             Context.exit();
         }
     }
 
     @Override
-    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws Exception
{
+    public void doGet(HttpServletRequest req, HttpServletResponse resp)
+            throws Exception {
         processRequest(req, resp);
     }
 
     @Override
-    public void doDelete(HttpServletRequest req, HttpServletResponse resp) throws Exception
{
+    public void doDelete(HttpServletRequest req, HttpServletResponse resp)
+            throws Exception {
         processRequest(req, resp);
     }
 
     @Override
-    public void doHead(HttpServletRequest req, HttpServletResponse resp) throws Exception
{
+    public void doHead(HttpServletRequest req, HttpServletResponse resp)
+            throws Exception {
         processRequest(req, resp);
     }
 
     @Override
-    public void doOptions(HttpServletRequest req, HttpServletResponse resp) throws Exception
{
+    public void doOptions(HttpServletRequest req, HttpServletResponse resp)
+            throws Exception {
         processRequest(req, resp);
     }
 
     @Override
-    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws Exception
{
+    public void doPost(HttpServletRequest req, HttpServletResponse resp)
+            throws Exception {
         processRequest(req, resp);
     }
 
     @Override
-    public void doPut(HttpServletRequest req, HttpServletResponse resp) throws Exception
{
+    public void doPut(HttpServletRequest req, HttpServletResponse resp)
+            throws Exception {
         processRequest(req, resp);
     }
 }

Modified: incubator/sling/whiteboard/microsling/src/main/webapp/server-side-javascript.html
URL: http://svn.apache.org/viewvc/incubator/sling/whiteboard/microsling/src/main/webapp/server-side-javascript.html?rev=585096&r1=585095&r2=585096&view=diff
==============================================================================
--- incubator/sling/whiteboard/microsling/src/main/webapp/server-side-javascript.html (original)
+++ incubator/sling/whiteboard/microsling/src/main/webapp/server-side-javascript.html Tue
Oct 16 03:18:07 2007
@@ -22,7 +22,8 @@
   	To test this, remove or rename <a href="velocity-scripts.html">Velocity templates</a>
     if you played with them before (Velocity has priority due to the order in which the SlingServlet
classes
     are setup),  and store the script shown
-  	below under <em> /sling/scripts/microsling/example/get.text_html.js</em> in
the repository.
+  	below under <em>/sling/scripts/microsling/example/get.text_html.js</em>
+  	or <em>/sling/scripts/microsling/example/get.text_html.esp</em> in the repository.
   </p>
   <p>
   	Content nodes created with the <a href="content-creation-forms.html">Content creation
forms</a>
@@ -35,18 +36,39 @@
     in the request.
   </p>
   <p>
+    Server-side javascript comes in two flavors: Raw javascript identified by the script
file
+    extension <em>.js</em> and templated javascript, which we call <em>ECMA
Server Pages</em>,
+    identified by the script file extension <em>.esp</em>. Templated javascript
works
+    much like JSP in that template text and javascript code may be mixed using the
+    <em>&lt;% ... %&gt;</em> tag to enclose code or the <em>&lt;%=
... %&gt;</em>
+    tag to include the result of evaluating the enclosed expression in the output. 
+  <p>
   	Raw server-side javascript is probably better suited for handling POST and PUT requests
(that would be
   	the <em>post.js</em> and <em>put.js</em> scripts), unless a suitable
templating library is used. 
   </p>
   <p>
+    <strong>get.js - An example of raw javascript</strong>
+  <p>
     <pre>
 // Not the best way of rendering output, of course...
 out.println("&lt;html>&lt;body>");
 out.println("&lt;p>This page is generated from a rhino script&lt;/p>");
 out.println("&lt;h1>" + resource.getURI() + "&lt;/h1>");
-out.println("&lt;p>Title: " + resource.getData().getProperty('title').getString()
+ "&lt;/p>");
-out.println("&lt;p>Text: " + resource.getData().getProperty('text').getString() +
"&lt;/p>");
+out.println("&lt;p>Title: " + resource.getItem().getProperty('title').getString()
+ "&lt;/p>");
+out.println("&lt;p>Text: " + resource.getItem().getProperty('text').getString() +
"&lt;/p>");
 out.println("&lt;/body>&lt;/html>");
+    </pre>
+  <p>
+    <strong>get.esp - An example of templated javascript</strong>
+  <p>
+    <pre>
+&lt;%-- ESP rendering of JavaScript --&gt;
+&lt;html&gt;&lt;body&gt;
+&lt;p&gt;This page is generated from a rhino script&lt;/p&gt;
+&lt;h1&gt;&lt;%= resource.getURI() %&gt;&lt;/h1&gt;
+&lt;p&gt;Title: &lt;%= resource.getItem().getProperty('title').getString() %&gt;&lt;/p&gt;
+&lt;p&gt;Text: &lt;%= resource.getItem().getProperty('text').getString() %&gt;&lt;/p&gt;
+&lt;/body&gt;&lt;/html&gt;
     </pre>
   </p>
   



Mime
View raw message