View Javadoc

1   /**
2    * Copyright (C) 2005-2009 Alfresco Software Limited.
3    *
4    * This file is part of the Spring Surf Extension project.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *  http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.springframework.extensions.webscripts.processor;
20  
21  import java.io.InputStream;
22  import java.io.Writer;
23  import java.util.HashMap;
24  import java.util.Map;
25  
26  import org.springframework.extensions.surf.core.processor.ProcessorExtension;
27  import org.springframework.extensions.surf.core.scripts.ScriptException;
28  import org.springframework.extensions.webscripts.ScriptContent;
29  import org.springframework.extensions.webscripts.processor.AbstractScriptProcessor;
30  
31  import com.caucho.quercus.Quercus;
32  import com.caucho.quercus.env.ArrayValue;
33  import com.caucho.quercus.env.ArrayValueImpl;
34  import com.caucho.quercus.env.BooleanValue;
35  import com.caucho.quercus.env.DoubleValue;
36  import com.caucho.quercus.env.Env;
37  import com.caucho.quercus.env.StringInputStream;
38  import com.caucho.quercus.env.StringValue;
39  import com.caucho.quercus.env.Value;
40  import com.caucho.quercus.module.QuercusModule;
41  import com.caucho.quercus.page.QuercusPage;
42  import com.caucho.util.CharBuffer;
43  import com.caucho.vfs.ReadStream;
44  import com.caucho.vfs.StringWriter;
45  import com.caucho.vfs.VfsStream;
46  import com.caucho.vfs.WriteStream;
47  
48  /**
49   * PHP Script Processor for Alfresco Web Framework
50   * 
51   * @author Roy Wetherall
52   * @author muzquiano
53   */
54  public class PHPScriptProcessor extends AbstractScriptProcessor
55  {	
56      /** Key to value found in $_SERVER indicating that the Alfresco API is available */
57      public static final String ALF_AVAILABLE = "ALF_AVAILABLE";
58          
59      /** Quercus engine */
60      private Quercus quercus;
61      
62      /**
63       * Constructor
64       */
65      public PHPScriptProcessor()
66      {
67      	// Create the quercus engine
68      	this.quercus = new Quercus();
69      	
70      	// Set the ALF_AVAILABLE server value to help with script reuse
71      	this.quercus.setServerEnv(PHPScriptProcessor.ALF_AVAILABLE, "true");
72      }
73         
74      /* (non-Javadoc)
75       * @see org.alfresco.processor.Processor#getExtension()
76       */
77      public String getExtension()
78      {
79          return "php";
80      }    
81      
82      /* (non-Javadoc)
83       * @see org.alfresco.processor.Processor#getName()
84       */
85      public String getName()
86      {
87      	return "php";
88      }
89      
90      /* (non-Javadoc)
91       * @see org.alfresco.web.scripts.processor.AbstractScriptProcessor#init()
92       */
93      public void init() 
94      {
95      	super.init();
96      	
97      	// TODO: any other initialization?
98      }
99      
100             
101     /* (non-Javadoc)
102      * @see org.alfresco.web.scripts.processor.BaseProcessor#registerProcessorExtension(org.alfresco.processor.ProcessorExtension)
103      */
104     public void registerProcessorExtension(ProcessorExtension processorExtension)
105     {
106         // Call the base implementation
107         super.registerProcessorExtension(processorExtension);
108         
109         // Deal with adding the extension to the quercus engine
110         if (processorExtension instanceof PHPMethodExtension)
111         {
112             this.quercus.addModule((QuercusModule)processorExtension);    
113             ((PHPMethodExtension)processorExtension).initialiseModule(this.quercus.findModule(processorExtension.getClass().getName()));
114         }
115         else if (processorExtension instanceof PHPObjectExtension)
116         {
117             try
118             {
119                 Class clazz = Class.forName(((PHPObjectExtension)processorExtension).getExtensionClass());
120                 this.quercus.addJavaClass(processorExtension.getExtensionName(), clazz);
121             }
122             catch (ClassNotFoundException exception)
123             {
124                 throw new PHPProcessorException("PHP Object Extension class '" + ((PHPObjectExtension)processorExtension).getExtensionClass() + "' could not be found.", exception);
125             }
126         }
127     }
128     
129     /**
130      * Executes a PHP script using the quercus engine.
131      * 
132      * @param script    the script as a string
133      * @param out       the writer to direct the output of the PHP to.  This can be null if no output is required.
134      * @param model     the context model for the script
135      * @return          the return result of the executed PHP
136      */
137     private Object executePHPScript(String script, Writer out, Map<String, Object> model)
138     {
139         return executePHPScript(new StringInputStream(script), out, model);
140     }
141     
142     /**
143      * Executes the PHP script using the quercus engine.
144      * 
145      * @param is        the input stream containing the PHP to execute
146      * @param out       the writer to direct the output of the PHP to.  This can be null if no output is required.
147      * @param model     the context model for the script
148      * @return Object   the return result of the executed PHP
149      */
150     private Object executePHPScript(InputStream is, Writer out, Map<String, Object> model)
151     {
152         try
153         {
154             // Create the string writer
155             StringWriter writer = new StringWriter(new CharBuffer(1024));
156             writer.openWrite();
157             
158             // Parse the page
159             VfsStream stream = new VfsStream(is, null);        
160             QuercusPage page = this.quercus.parse(new ReadStream(stream));
161             
162             // Execute the page
163             WriteStream ws = new WriteStream(writer);
164             Env env = new Env(this.quercus, page, ws, null, null);   
165             env.start();
166                         
167             // Execute the page
168             Value value = page.executeTop(env);
169             
170             // Make sure we flush because otherwise the result does not get written
171             ws.flush();
172            
173             // Write to output
174             String result = ((StringWriter)ws.getSource()).getString();            
175             if (out != null)
176             {
177                 out.write(result);
178             }            
179             
180             // Return the result
181             return value.toJavaObject();
182         }
183         catch (Exception exception)
184         {
185             throw new ScriptException("Error executing script.", exception);
186         }
187     }
188         
189     /**
190      * 
191      * @param model
192      * @return
193      */
194     @SuppressWarnings("unchecked")
195     private Map<String, Object> getModel(Object model)
196     {
197         Map<String, Object> result = null;
198         if (model != null && model instanceof Map)
199         {
200             result = (Map<String, Object>)model;
201         }
202         else
203         {
204             result = new HashMap<String, Object>(2);
205         }
206         return result;
207     }
208 
209     /* (non-Javadoc)
210      * @see org.alfresco.web.scripts.ScriptProcessor#findScript(java.lang.String)
211      */
212     public ScriptContent findScript(String path)
213     {
214     	return getScriptLoader().getScript(path);    	
215     }
216     
217     /* (non-Javadoc)
218      * @see org.alfresco.web.scripts.ScriptProcessor#executeScript(java.lang.String, java.util.Map)
219      */
220     public Object executeScript(String path, Map<String, Object> model)
221     {
222     	ScriptContent scriptContent = getScriptLoader().getScript(path);
223     	return executeScript(scriptContent, model);
224     }
225 
226     /* (non-Javadoc)
227      * @see org.alfresco.web.scripts.ScriptProcessor#executeScript(org.alfresco.web.scripts.ScriptContent, java.util.Map)
228      */
229     public Object executeScript(ScriptContent location, Map<String, Object> model)
230     {
231     	return executePHPScript(location.getInputStream(), null, model);    	
232     }
233 
234     /* (non-Javadoc)
235      * @see org.alfresco.web.scripts.ScriptProcessor#unwrapValue(java.lang.Object)
236      */
237     public Object unwrapValue(Object value)
238     {
239         Value result = null;
240         
241         if (value instanceof String)
242         {
243             result = StringValue.create(value);
244         }
245         else if (value instanceof Integer)
246         {  
247             // TODO could do with a IntegerValue value ...
248             result = DoubleValue.create(((Integer)value).doubleValue());
249         }
250         else if (value instanceof Boolean)
251         {
252         	result = BooleanValue.create((Boolean)value);
253         }
254         else if (value instanceof Map)
255         {
256             Map map = (Map)value;
257             ArrayValue arrayValue = new ArrayValueImpl(map.size());
258             for (Object objKey : map.keySet())
259             {
260                 if (objKey instanceof String)
261                 {
262                     String key = (String)objKey;
263                     Object objValue = map.get(key);
264                     arrayValue.put(StringValue.create(key), (Value) unwrapValue(objValue));
265                 }
266             }
267             result = arrayValue;
268         }
269         
270         return result;
271     }
272     
273     /* (non-Javadoc)
274      * @see org.alfresco.web.scripts.ScriptProcessor#reset()
275      */
276     public void reset()
277     {    	
278     	init();
279     }
280 }