001 
002 /*
003  *  Descripter 1.0 - Java Script Engines
004  *  Copyright (C) 2010-2015  Jianjun Liu (J.J.Liu)
005  *  
006  *  This program is free software: you can redistribute it and/or modify
007  *  it under the terms of the GNU Affero General Public License as published by
008  *  the Free Software Foundation, either version 3 of the License, or
009  *  (at your option) any later version.
010  *  
011  *  This program is distributed in the hope that it will be useful,
012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014  *  GNU Affero General Public License for more details.
015  *  
016  *  You should have received a copy of the GNU Affero General Public License
017  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
018  */
019 
020 package org.descripter.js.ss;
021 
022 import java.io.File;
023 import java.io.FileNotFoundException;
024 import java.io.FileReader;
025 import java.io.IOException;
026 import java.util.HashMap;
027 import java.util.Map;
028 
029 import org.descripter.js.Descripter;
030 import org.descripter.js.Memory;
031 
032 /**
033  * <p>Manages descripted and compiled executables for the server-side scriptlet and pages.</p>
034  * 
035  * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.descripter.org" target="_blank">http://www.descripter.org</a>
036  * @since Descripter 1.0
037  */
038 public class Executable
039 {
040     /**
041      * <p>The class of the executable.</p>
042      * @since Descripter 1.0
043      */
044     protected final Class<?> clazz;
045     /**
046      * <p>The time-stamp of the executable.</p>
047      * @since Descripter 1.0
048      */
049     protected final long stamp;
050 
051     /**
052      * <p>Constructs an executable object.</p>
053      * @param file A requested source file
054      * @param clazz The compiled executable class
055      * @since Descripter 1.0
056      */
057     protected Executable(File file, Class<?> clazz) {
058         this.stamp = file.lastModified();
059         this.clazz = clazz;
060     }
061 
062     /**
063      * <p>Executes this executable in a given {@link Scriptlet}.</p>
064      * @param s A {@link Scriptlet} for executing this executable
065      * @return The return result of the execution
066      * @throws IOExeption if an {@link IOException} happens when executing
067      * @since Descripter 1.0
068      */
069     public Object execute(Scriptlet<?> s) throws IOException {
070         s.prelude();
071         Object ret = s.execute(clazz);
072         s.finale();
073         return ret;
074     }
075 
076     /**
077      * <p>Determines if an update for the current executable from the specified {@link File} is unnecessary.</p>
078      * @param file A {@link File}
079      * @return <tt>true</tt> if an update is unnecessary; <tt>false</tt>, otherwise.
080      * @since Descripter 1.0
081      */
082     public boolean updated(File file) {
083         return stamp >= file.lastModified();
084     }
085 
086     private static final Map<String, Executable> map = new HashMap<String, Executable>();
087     private static final Memory memo = new Memory(true);
088     private static int next = 0;
089 
090     /**
091      * <p>Statically gets or creates an executable.</p>
092      * @param scriptlet A {@link Scriptlet} to compile and/or descript the source file
093      * @param file A {@link File} of Server-Side JavaScript source or JavaScript Server Page
094      * @param jssp <tt>true</tt> if the source file is a JavaScript Server Page; otherwise, it is 
095      * Server-Side JavaScript source.
096      * @return The existing or newly created executable.
097      * @since Descripter 1.0
098      */
099     public static synchronized final Executable get(Scriptlet<?> scriptlet, File file, boolean jssp)
100             throws FileNotFoundException, ClassNotFoundException {
101         String path = file.getAbsolutePath();
102         if (map.containsKey(path)) {
103             Executable x = map.get(path);
104             if (x.updated(file)) {
105                 return x;
106             }
107         }
108         String name = "J_S_S_" + next++;
109         String java = jssp ? new Descripter(scriptlet).descript(
110                 name,
111                 new Scriptizer(scriptlet).scriptize(
112                         new FileReader(file)
113                 )
114         ) : new Descripter(scriptlet).descript(
115                 name,
116                 new FileReader(file)
117         );
118         if (memo.compile(name, java)) {
119             map.put(
120                     path,
121                     new Executable(
122                             file,
123                             memo.loadClass(name)
124                     )
125             );
126         }
127         return map.get(path);
128     }
129 }