Package org.apache.portals.bridges.script

Source Code of org.apache.portals.bridges.script.ScriptPortlet

/*
* 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.portals.bridges.script;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.EventPortlet;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
import javax.portlet.GenericPortlet;
import javax.portlet.Portlet;
import javax.portlet.PortletConfig;
import javax.portlet.PortletException;
import javax.portlet.PreferencesValidator;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import javax.portlet.ResourceServingPortlet;
import javax.script.ScriptEngine;
import javax.script.ScriptException;

/**
* ScriptPortlet evaluates a script source to create a delegatee portlet instance
* and delegate invocations to the delegatee scripted portlet instance.
* <P>
* The final evaluated object from the scripted portlet source must be a portlet instance or portlet class
* based on the Java Portlet Specifications.
* </P>
* <P>
* Here's an example portlet definition with descriptions on init parameters.
* </P>
* <PRE><CODE><XMP>
* <portlet>
*   <portlet-name>HelloGroovy</portlet-name>
*   <display-name>Hello Groovy</display-name>
*   <portlet-class>org.apache.portals.bridges.script.ScriptPortlet</portlet-class>
*  
*   <!-- Optional init parameter for script engine
*   If this init parameter is not set, the ScriptPortlet will look up a script engine automatically
*   by the mimeType or the extension of the script source file. -->
*   <init-param>
*     <name>engine</name>
*     <!--
*       Note: You can set other script engine which support JSR-223 ScriptEngine
*       such as 'groovy', 'jruby', 'jython'.
*     -->
*     <value>groovy</value>
*   </init-param>
*  
*   <!-- Optional init parameter for the key for portlet/preferencesValidator class or portlet/preferencesValidator instance which is evaluated and returned by the script.
*   By default, when this init parameter is not set, ScriptPortlet retrieves the last evaluated object from the script.
*   If you set this to 'value', then ScriptPortlet retrieves an object named 'value' from the bindings of the script engine.
*   Depending on script engines, this init parameter should be properly configured because some script engines do not return the last evaluated object. -->
*   <init-param>
*     <name>eval-key</name>
*     <value>value</value>
*   </init-param>
*  
*   <!-- Required init parameter for script source path -->
*   <init-param>
*     <name>source</name>
*     <!--
*       Note: You can set script source in three ways.
*       The first is to use context relative path,
*       the second is to use file: url,
*       and the third is to classpath: uri.
*       Here are the examples for each way.
*     -->
*     <!--
*       <value>/WEB-INF/groovy/HelloGroovy.groovy</value>
*       <value>file:/C:/Program Files/Apache Software Foundation/Tomcat/webapps/demo/WEB-INF/groovy/HelloGroovy.groovy</value>
*       <value>classpath:org/apache/portals/bridges/script/HelloGroovy.groovy</value>
*     -->
*     <value>classpath:org/apache/portals/bridges/script/HelloGroovy.groovy</value>
*   </init-param>
*  
*   <!-- Optional init parameter for script file content encoding. The default value is 'UTF-8'. -->
*   <init-param>
*     <name>encoding</name>
*     <value>UTF-8</value>
*   </init-param>
*  
*   <!-- Optional init parameter for auto-refresh option.
*   If auto-refresh is true, then a modification of script source can be refreshed automatically.
*   By default, this option is set to false. -->
*   <init-param>
*     <name>auto-refresh</name>
*     <value>true</value>
*   </init-param>
*  
*   <!-- Optional init parameter for refresh-delay option.
*   When auto-refresh is true, this init parameter sets the milliseconds of automatic refreshing interval.
*   By default, this option is set to 60000 milliseconds (a minute). -->
*   <init-param>
*     <name>refresh-delay</name>
*     <value>60000</value>
*   </init-param>
*  
*   <!-- Optional init parameter for script preferences validator path -->
*   <init-param>
*     <name>validator</name>
*     <!--
*       Note: You can set script preferences validator source in three ways.
*       The first is to use context relative path,
*       the second is to use file: url,
*       and the third is to classpath: uri.
*       Here are the examples for each way.
*     -->
*     <!--
*       <value>/WEB-INF/groovy/HelloGroovyPrefsValidator.groovy</value>
*       <value>file:/C:/Program Files/Apache Software Foundation/Tomcat/webapps/demo/WEB-INF/groovy/HelloGroovyPrefsValidator.groovy</value>
*       <value>classpath:org/apache/portals/bridges/script/HelloGroovyPrefsValidator.groovy</value>
*     -->
*     <value>classpath:org/apache/portals/bridges/script/HelloGroovyPrefsValidator.groovy</value>
*   </init-param>
*  
*   <!-- The followings are not special for ScriptPortlet, but normal configurations for a portlet. -->
*   <supports>
*     <mime-type>text/html</mime-type>
*     <portlet-mode>VIEW</portlet-mode>
*     <portlet-mode>EDIT</portlet-mode>
*     <portlet-mode>HELP</portlet-mode>
*   </supports>
*   <supported-locale>en</supported-locale>
*   <portlet-info>
*     <title>Hello Groovy</title>
*     <short-title>Hello Groovy</short-title>
*     <keywords>demo,groovy</keywords>
*   </portlet-info>
*   <portlet-preferences>
*     <preference>
*       <name>message</name>
*       <value>Hello, Groovy!</value>
*     </preference>
*     <preferences-validator>org.apache.portals.bridges.script.ScriptPortletPreferencesValidator</preferences-validator>
*   </portlet-preferences>
*  
* </portlet>
* </XMP></CODE></PRE>
*
* @author <a href="mailto:woonsan@apache.org">Woonsan Ko</a>
* @version $Id: ScriptPortlet.java 937248 2010-04-23 11:06:13Z woonsan $
*/
public class ScriptPortlet extends GenericPortlet
{
    public static final String ENGINE = "engine";
   
    public static final String EVAL_KEY = "eval-key";
   
    public static final String SOURCE = "source";
   
    public static final String VALIDATOR = "validator";
   
    public static final String URI_ENCODING = "uri-encoding";
   
    public static final String ENCODING = "encoding";
   
    public static final String AUTO_REFRESH = "auto-refresh";
   
    public static final String REFRESH_DELAY = "refresh-delay";
   
    public static final String SCRIPT_SOURCE_FACTORY = "script-source-factory";
   
    private PortletConfig portletConfig;
   
    private String scriptEngineName;
   
    private String evalKey;
   
    private ScriptEngine scriptEngine;
   
    private String scriptSourceUri;
   
    private String scriptSourceUriEncoding;
   
    private String scriptSourceCharacterEncoding;
   
    private boolean autoRefresh;
   
    private long refreshDelay = 60000L;
   
    private ScriptSource scriptSource;
   
    private long scriptSourceLastEvalStarted;
   
    private long scriptSourceLastEvaluated;
   
    private long scriptSourceLastModified;
   
    private Portlet scriptPortletInstance;
   
    private GenericPortlet scriptGenericPortletInstance;
   
    private Method portletDoEditMethod;
   
    private String validatorSourceUri;
   
    private ScriptSource validatorSource;
   
    private long validatorSourceLastEvalStarted;
   
    private long validatorSourceLastEvaluated;
   
    private long validatorSourceLastModified;
   
    private PreferencesValidator validatorInstance;
   
    private static ThreadLocal<PreferencesValidator> tlCurrentValidatorInstance = new ThreadLocal<PreferencesValidator>();
   
    private ScriptSourceFactory scriptSourceFactory = new SimpleScriptSourceFactory();
   
    public ScriptPortlet()
    {
        super();
    }
   
    @Override
    public void init(PortletConfig config) throws PortletException
    {
        portletConfig = config;
       
        String param = config.getInitParameter(ENGINE);
       
        if (param != null && !"".equals(param.trim()))
        {
            scriptEngineName = param;
        }
       
        param = config.getInitParameter(EVAL_KEY);
       
        if (param != null && !"".equals(param.trim()))
        {
            evalKey = param;
        }
       
        autoRefresh = "true".equals(config.getInitParameter(AUTO_REFRESH));
       
        param = config.getInitParameter(REFRESH_DELAY);
       
        if (param != null && !"".equals(param.trim()))
        {
            refreshDelay = Long.parseLong(param.trim());
        }
       
        param = config.getInitParameter(SCRIPT_SOURCE_FACTORY);
       
        if (param != null && !"".equals(param.trim()))
        {
            try
            {
                scriptSourceFactory = (ScriptSourceFactory) Thread.currentThread().getContextClassLoader().loadClass(param).newInstance();
            }
            catch (Exception e)
            {
                throw new PortletException("Configuration failed: " + SCRIPT_SOURCE_FACTORY + ". Cannot create script source factory: " + param);
            }
        }
       
        param = config.getInitParameter(ENCODING);
       
        if (param != null && !"".equals(param.trim()))
        {
            scriptSourceCharacterEncoding = param;
        }
       
        param = config.getInitParameter(URI_ENCODING);
       
        if (param != null && !"".equals(param.trim()))
        {
            scriptSourceUriEncoding = param;
        }
       
        scriptSourceUri = config.getInitParameter(SOURCE);

        if (scriptSourceUri == null)
        {
            throw new PortletException("Configuration failed: " + SOURCE + " should be set properly!");
        }
        else
        {
            try
            {
                if (scriptSourceUri.startsWith("/"))
                {
                    scriptSource = scriptSourceFactory.createScriptSource(new File(config.getPortletContext().getRealPath(scriptSourceUri)).toURL().toString(), scriptSourceUriEncoding, scriptSourceCharacterEncoding);
                }
                else
                {
                    scriptSource = scriptSourceFactory.createScriptSource(scriptSourceUri, scriptSourceUriEncoding, scriptSourceCharacterEncoding);
                }
               
                scriptSource.setMimeType(config.getPortletContext().getMimeType(scriptSource.getName()));
            }
            catch (Exception e)
            {
                throw new PortletException("Script not found: " + this.scriptSourceUri, e);
            }
        }
       
        refreshPortletInstance();

        if (scriptPortletInstance == null)
        {
            throw new PortletException("Script portlet is not available!");
        }
       
        validatorSourceUri = config.getInitParameter(VALIDATOR);

        if (validatorSourceUri != null)
        {
            try
            {
                if (validatorSourceUri.startsWith("/"))
                {
                    validatorSource = scriptSourceFactory.createScriptSource(new File(config.getPortletContext().getRealPath(validatorSourceUri)).toURL().toString(), scriptSourceUriEncoding, scriptSourceCharacterEncoding);
                }
                else
                {
                    validatorSource = scriptSourceFactory.createScriptSource(validatorSourceUri, scriptSourceUriEncoding, scriptSourceCharacterEncoding);
                }
               
                validatorSource.setMimeType(config.getPortletContext().getMimeType(validatorSource.getName()));
            }
            catch (Exception e)
            {
                throw new PortletException("Script not found: " + validatorSourceUri, e);
            }
           
            refreshValidatorInstance();
        }
       
    }
   
    @Override
    public void destroy()
    {
        if (scriptPortletInstance != null)
        {
            scriptPortletInstance.destroy();
        }
    }
   
    @Override
    public PortletConfig getPortletConfig ()
    {
        return portletConfig;
    }
   
    @Override
    public void render(RenderRequest request, RenderResponse response) throws PortletException, IOException
    {
        refreshPortletInstance();

        if (scriptPortletInstance == null)
        {
            throw new PortletException("Script portlet is not available!");
        }

        scriptPortletInstance.render(request, response);
    }
   
    @Override
    public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException
    {
        refreshPortletInstance();

        if (scriptPortletInstance == null)
        {
            throw new PortletException("Script portlet is not available!");
        }
        else
        {
            try
            {
                refreshValidatorInstance();
               
                if (validatorInstance != null)
                {
                    tlCurrentValidatorInstance.set(validatorInstance);
                }
               
                scriptPortletInstance.processAction(request, response);
            }
            finally
            {
                if (validatorInstance != null)
                {
                    tlCurrentValidatorInstance.set(null);
                }
            }
        }
    }
   
    @Override
    public void processEvent(EventRequest request, EventResponse response) throws PortletException, IOException
    {
        if (scriptPortletInstance == null)
        {
            throw new PortletException("Script portlet is not available!");
        }
       
        if (scriptPortletInstance instanceof EventPortlet)
        {
            ((EventPortlet) scriptPortletInstance).processEvent(request, response);
        }
    }
   
    @Override
    public void serveResource(ResourceRequest request, ResourceResponse response) throws PortletException, IOException
    {
        if (scriptPortletInstance == null)
        {
            throw new PortletException("Script portlet is not available!");
        }
       
        if (scriptPortletInstance instanceof ResourceServingPortlet)
        {
            ((ResourceServingPortlet) scriptPortletInstance).serveResource(request, response);
        }
    }
   
    @Override
    public void doEdit(RenderRequest request, RenderResponse response) throws PortletException, IOException
    {
        if (scriptPortletInstance == null)
        {
            throw new PortletException("Script portlet is not available!");
        }
       
        if (scriptGenericPortletInstance != null && portletDoEditMethod != null)
        {
            try
            {
                portletDoEditMethod.invoke(scriptGenericPortletInstance, new Object [] { request, response });
            }
            catch (Exception e)
            {
                throw new PortletException("Failed to invoke doEdit method.", e);
            }
        }
        else
        {
            throw new PortletException("doEdit method not implemented or not public.");
        }
    }
   
    protected void refreshPortletInstance() throws PortletException
    {
        boolean scriptCreated = (scriptPortletInstance != null);
        boolean scriptModified = false;
        long checkedScriptSourceLastModified = 0L;
       
        if (scriptCreated)
        {
            if (autoRefresh)
            {
                if ((refreshDelay <= 0L) || (System.currentTimeMillis() - scriptSourceLastEvalStarted > refreshDelay))
                {
                    scriptModified = (ScriptEngineUtils.isScriptModified(scriptSource, scriptSourceLastModified));
                }
            }
           
            if (scriptModified)
            {
                checkedScriptSourceLastModified = scriptSource.lastModified();
            }
            else
            {
                return;
            }
        }
       
        try
        {
            synchronized (this)
            {
                if ((scriptModified && scriptSourceLastEvaluated >= checkedScriptSourceLastModified) || (!scriptCreated && scriptPortletInstance != null))
                {
                    return;
                }
               
                scriptSourceLastModified = checkedScriptSourceLastModified;
                scriptSourceLastEvalStarted = System.currentTimeMillis();
                Portlet tempScriptPortletInstance = null;
                if (scriptEngine == null)
                {
                    scriptEngine = ScriptEngineUtils.createScriptEngine(scriptEngineName, scriptSource);
                }
                Object evalPortlet = ScriptEngineUtils.evaluateScript(scriptEngine, scriptSource, evalKey, true);
                scriptSourceLastEvaluated = System.currentTimeMillis();
                   
                if (evalPortlet instanceof Portlet)
                {
                    tempScriptPortletInstance = (Portlet) evalPortlet;
                }
                else if (evalPortlet instanceof Class)
                {
                    Class<? extends Portlet> scriptPortletClass = (Class<? extends Portlet>) evalPortlet;
                    tempScriptPortletInstance = (Portlet) scriptPortletClass.newInstance();
                }
                else
                {
                    throw new ScriptException("The evaluated return is neither class nor instance of javax.portlet.Portlet. " + evalPortlet);
                }
               
                scriptGenericPortletInstance = null;
                portletDoEditMethod = null;
               
                if (tempScriptPortletInstance instanceof GenericPortlet)
                {
                    scriptGenericPortletInstance = (GenericPortlet) tempScriptPortletInstance;
                   
                    try
                    {
                        Method doEditMethod = scriptGenericPortletInstance.getClass().getMethod("doEdit", new Class [] { RenderRequest.class, RenderResponse.class });
                       
                        if (Modifier.isPublic(doEditMethod.getModifiers()))
                        {
                            portletDoEditMethod = doEditMethod;
                        }
                    }
                    catch (NoSuchMethodException e)
                    {
                    }
                }
               
                tempScriptPortletInstance.init(portletConfig);
               
                scriptPortletInstance = tempScriptPortletInstance;
            }
        }
        catch (Exception ex)
        {
            throw new PortletException("Could not evaluate script: " + scriptSourceUri, ex);
        }
    }
   
    protected void refreshValidatorInstance() throws PortletException
    {
        if (validatorSource == null)
        {
            return;
        }
       
        boolean scriptCreated = (validatorInstance != null);
        boolean scriptModified = false;
        long checkedScriptSourceLastModified = 0L;
       
        if (scriptCreated)
        {
            if (autoRefresh)
            {
                if ((refreshDelay <= 0L) || (System.currentTimeMillis() - validatorSourceLastEvalStarted > refreshDelay))
                {
                    scriptModified = (ScriptEngineUtils.isScriptModified(validatorSource, validatorSourceLastModified));
                }
            }
           
            if (scriptModified)
            {
                checkedScriptSourceLastModified = validatorSource.lastModified();
            }
            else
            {
                return;
            }
        }
       
        try
        {
            synchronized (this)
            {
                if ((scriptModified && validatorSourceLastEvaluated >= checkedScriptSourceLastModified) || (!scriptCreated && validatorInstance != null))
                {
                    return;
                }
               
                validatorSourceLastModified = checkedScriptSourceLastModified;
                validatorSourceLastEvalStarted = System.currentTimeMillis();
                PreferencesValidator tempValidatorInstance = null;
                Object evalPortlet = ScriptEngineUtils.evaluateScript(scriptEngine, validatorSource, evalKey, true);
                validatorSourceLastEvaluated = System.currentTimeMillis();
                   
                if (evalPortlet instanceof PreferencesValidator)
                {
                    tempValidatorInstance = (PreferencesValidator) evalPortlet;
                }
                else if (evalPortlet instanceof Class)
                {
                    Class<? extends PreferencesValidator> validatorClass = (Class<? extends PreferencesValidator>) evalPortlet;
                    tempValidatorInstance = (PreferencesValidator) validatorClass.newInstance();
                }
                else
                {
                    throw new ScriptException("The evaluated return is neither class nor instance of javax.portlet.PreferencesValidator. " + evalPortlet);
                }
               
                validatorInstance = tempValidatorInstance;
            }
        }
        catch (Exception ex)
        {
            throw new PortletException("Could not evaluate script: " + validatorSourceUri, ex);
        }
    }
   
    protected Portlet getScriptPortletInstance()
    {
        return scriptPortletInstance;
    }
   
    protected long getScriptSourceLastEvaluated()
    {
        return scriptSourceLastEvaluated;
    }
   
    protected long setRefreshDelay()
    {
        return refreshDelay;
    }
   
    protected void setRefreshDelay(long refreshDelay)
    {
        this.refreshDelay = refreshDelay;
    }
   
    protected ScriptSource getScriptSource()
    {
        return scriptSource;
    }
   
    protected ScriptSource getValidatorSource()
    {
        return validatorSource;
    }
   
    protected PreferencesValidator getValidatorInstance()
    {
        return validatorInstance;
    }
   
    protected ScriptSourceFactory getScriptSourceFactory()
    {
        return scriptSourceFactory;
    }
   
    protected void setScriptSourceFactory(ScriptSourceFactory scriptSourceFactory)
    {
        this.scriptSourceFactory = scriptSourceFactory;
    }
   
    protected static PreferencesValidator getCurrentValidatorInstance()
    {
        return (PreferencesValidator) tlCurrentValidatorInstance.get();
    }
}
TOP

Related Classes of org.apache.portals.bridges.script.ScriptPortlet

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.