/* * 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.tuscany.sca.implementation.web.client; import java.io.IOException; import java.io.PrintWriter; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.tuscany.sca.core.ExtensionPointRegistry; import org.apache.tuscany.sca.core.invocation.ExtensibleProxyFactory; import org.apache.tuscany.sca.interfacedef.java.JavaInterface; import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; import org.directwebremoting.Container; import org.directwebremoting.create.AbstractCreator; import org.directwebremoting.extend.CreatorManager; import org.directwebremoting.extend.Handler; import org.directwebremoting.extend.Remoter; import org.directwebremoting.servlet.DwrServlet; import org.directwebremoting.servlet.EngineHandler; import org.directwebremoting.servlet.PathConstants; import org.directwebremoting.servlet.UrlProcessor; /** * Tuscany customized DWR Servlet to implement support for the DWR binding * * Handles requests for SCA services and references that use <binding.dwr> */ public class ClientServlet extends DwrServlet { private static final long serialVersionUID = 1L; private transient Map<String, RuntimeEndpointReference> serviceRefs; // private transient List<String> referenceNames; private transient boolean initialized; private transient Map<String, String> initParams; public static final String SCRIPT_PATH = "/org.oasisopen.sca.componentContext.js"; public ClientServlet() { this.serviceRefs = new HashMap<String, RuntimeEndpointReference>(); // this.referenceNames = new ArrayList<String>(); this.initParams = new HashMap<String, String>(); // maybe use <binding.dwr> attributes to define the init params initParams.put("activeReverseAjaxEnabled", "true"); } @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { super.service(req, res); } /** * Initialize the Servlet * There is a single instance of this Servlet which is registered * for multiple path mappings, but the init should only run once. */ @Override public void init(ServletConfig servletConfig) throws ServletException { if (!initialized) { super.init(patchConfig(servletConfig)); addScriptHandler(); // initServices(); initialized = true; } } /** * Add in the handler to process the HTTP get for /sca/scaDomain.js * * This wrappers the DWR Engine handler which returns the DWR engine.js script, * this wrappers that handler so as to add Tuscany specific header and footer code * to the DWR engine.js to define the Tuscany SCADomain control functions and * functions for each SCA service and reference that use <binding.dwr>. */ private void addScriptHandler() { UrlProcessor urlProcessor = (UrlProcessor)getContainer().getBean(UrlProcessor.class.getName()); final EngineHandler engineHandler = (EngineHandler)getContainer().getBean(PathConstants.URL_PREFIX + "/engine.js"); final Handler scaDomainScriptHandler = new Handler() { public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException { PrintWriter out = response.getWriter(); out.println("/** Apache Tuscany componentContext.js Header */"); engineHandler.handle(request, response); tuscanyFooter(request, out); } }; // add the scaDomainScriptHandler to the urlProcessor // bit of a hack, there's probably cleaner way to get it registered urlProcessor.afterContainerSetup(new Container() { public Object getBean(String name) { return scaDomainScriptHandler; } public Collection<?> getBeanNames() { return Arrays.asList(new String[] {PathConstants.URL_PREFIX + SCRIPT_PATH}); } }); } /** * Adds the JavaScript defining SCADomain, its control functions, * and functions for all the available SCA services and references. */ private void tuscanyFooter(HttpServletRequest request, PrintWriter out) { out.println("if (SCA == undefined) var SCA = new Object();"); out.println("if (SCA.componentContext == undefined) {"); out.println(" SCA.componentContext = new Object();"); out.println(" SCA.componentContext.serviceNames = [];"); out.println(" SCA.componentContext.serviceProxys = [];"); out.println(" SCA.componentContext.getService = function(serviceName){"); out.println(" var i = SCA.componentContext.serviceNames.indexOf(serviceName);"); out.println(" return SCA.componentContext.serviceProxys[i];"); out.println(" };"); out.println(" if (componentContext == undefined) var componentContext = SCA.componentContext;"); out.println("}"); // out.println("/** Apache Tuscany scaDomain.js Footer */"); // out.println(); // out.println("function scaDomain() { }"); // out.println(); // out.println("// SCA services"); // Use the DWR remoter to generate the JavaScipt function for each SCA service Remoter remoter = (Remoter)getContainer().getBean(Remoter.class.getName()); for (String serviceName : serviceRefs.keySet()) { String path = request.getServletPath() + "/" + serviceName; String serviceScript = remoter.generateInterfaceScript(serviceName, path); out.println(serviceScript); out.println("SCA.componentContext.serviceNames.push('" + serviceName + "');"); out.println("SCA.componentContext.serviceProxys.push(" + serviceName + ");"); // ServiceHolder s = services.get(serviceName); // final Class<?> iface = ((JavaInterface)s.cr.getInterfaceContract().getInterface()).getJavaClass(); // for (Method m : iface.getMethods()) { // out.println("if (" + serviceName + " == null) var " + serviceName + " = {};"); // out.println("SCA.componentContext.serviceNames.push('" + serviceName + "');"); //// out.println("SCA.componentContext.serviceProxys.push(new JSONRpcClient('" + serviceName + "').Service);"); // out.println(serviceName + "." + m.getName() + " = function(p0, callback) {"); // out.println(" dwr.engine._execute(" + serviceName + "._path, '" + serviceName + "', '" + m.getName() + "', p0, callback);"); // out.println(" }"); // } } // if (referenceNames.size() > 0) { // // out.println("// SCA reverse ajax control functions"); // out.println(); // out.println("scaDomain.open = function() { dwr.engine.setActiveReverseAjax(true); };"); // out.println("scaDomain.close = function() { dwr.engine.setActiveReverseAjax(false); };"); // // out.println(); // out.println("// SCA references"); // out.println(); // // // the JavaScript function for SCA references has an // // empty impl as it uses DWR severside "push" // for (String referenceName : referenceNames) { // out.println("function " + referenceName + "() { }"); // } // } out.println(); out.println("/** End of Apache Tuscany componentContext.js */"); out.println(); } // /** // * Add an SCA reference to be added to the DWR runtime // */ // public void addReference(String name) { // referenceNames.add(name); // } /** * Add an SCA service to be added to the DWR runtime */ public void addService(RuntimeEndpointReference epr) { CreatorManager creatorManager = (CreatorManager)getContainer().getBean(CreatorManager.class.getName()); addService(creatorManager, epr); serviceRefs.put(epr.getReference().getName(), epr); } private void addService(CreatorManager creatorManager, final RuntimeEndpointReference epr) { final Class<?> iface = ((JavaInterface)epr.getComponentTypeReferenceInterfaceContract().getInterface()).getJavaClass(); creatorManager.addCreator(epr.getReference().getName(), new AbstractCreator() { public Class<?> getType() { return iface; } public Object getInstance() throws InstantiationException { ExtensionPointRegistry registry = epr.getCompositeContext().getExtensionPointRegistry(); ExtensibleProxyFactory proxyFactory = ExtensibleProxyFactory.getInstance(registry); return proxyFactory.createProxy(iface, epr); } }); } /** * Patch the ServletConfig to enable setting init params for DWR * and so DWR can't see the Tuscany servlet's init params. */ private ServletConfig patchConfig(final ServletConfig servletConfig) { ServletConfig patchedContext = new ServletConfig() { public String getInitParameter(String name) { return initParams.get(name); } public Enumeration<?> getInitParameterNames() { return Collections.enumeration(initParams.keySet()); } public ServletContext getServletContext() { return servletConfig.getServletContext(); } public String getServletName() { return servletConfig.getServletName(); } }; return patchedContext; } }