Commit 6981149c authored by Philippe Merle's avatar Philippe Merle
Browse files

* Generated <ComponentName>.js automatically from binding metadata found into composite files.

  -> Removed Widget.js from examples/helloworld-widget as now this file is generated automatically.
* Generated Java classes for <implementation.widget> when its enclosing <component> has some <reference> and <property> children.
* Added checking for <implementation.widget default="...">
parent 405388c7
......@@ -42,11 +42,7 @@
<service name="Resource">
<tuscany:binding.http uri="/SayHelloWidget"/>
</service>
<!--
<reference name="sayHello" target="SayHello/SayHello">
<binding.ws/>
</reference>
-->
<reference name="sayHello" target="SayHello/SayHello"/>
</component>
</composite>
function includeJs(jsFilePath, callback) {
var js = document.createElement("script");
js.type = "text/javascript";
js.onload = callback
js.src = jsFilePath;
document.head.appendChild(js);
}
<!-- the object to talk to the SayHello Web service. -->
var sayHello;
<!-- Following generates and retrieves a JavaScript client for the SayHello Web service. -->
includeJs("/SayHello?js",
function() {
sayHello = new widget_helloworld_examples_frascati_ow2_org__SayHelloPortType_widget_helloworld_examples_frascati_ow2_org__SayHelloPort()
}
)
/**
* OW2 FraSCAti: SCA Implementation Widget
* Copyright (C) 2012 Inria, University of Lille 1
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* Contact: frascati@ow2.org
*
* Author: Philippe Merle
*
* Contributor:
*
*/
package org.ow2.frascati.implementation.widget;
import java.io.PrintWriter;
/**
* OW2 FraSCAti implementation widget binding info class.
*
* @author Philippe Merle - INRIA
* @version 1.5
*/
public class BindingInfo
{
//---------------------------------------------------------------------------
// Internal state.
// --------------------------------------------------------------------------
/**
* Name of the SCA reference.
*/
private String referenceName;
/**
* Java interface of the SCA reference.
*/
private Class<?> javaInterface;
/**
* URI where the SCA service is bound.
*/
private String uri;
/**
* Name of the Apache CXF JavaScript proxy.
*/
private String apacheCxfProxyName;
//---------------------------------------------------------------------------
// Constructor.
// --------------------------------------------------------------------------
/**
* Constructs a binding info.
*/
public BindingInfo(String referenceName, Class<?> javaInterface, String uri)
{
this.referenceName = referenceName;
this.javaInterface = javaInterface;
this.uri = uri;
computeApacheCxfJavaScriptProxyName();
}
//---------------------------------------------------------------------------
// Internal methods.
// --------------------------------------------------------------------------
/**
* Compute the Apache CXF JavaScript proxy name associated to the Java interface.
*/
private void computeApacheCxfJavaScriptProxyName()
{
String simpleName = javaInterface.getSimpleName();
// compute a prefix for the enclosing packages of this Java interface.
String[] packages = javaInterface.getPackage().getName().split("\\.");
StringBuilder sb = new StringBuilder();
for(int i=packages.length-1; i >= 0; i--) {
sb.append(packages[i]);
sb.append('_');
}
String prefix = sb.toString();
// compute the Apache CXF JavaScript proxy name.
apacheCxfProxyName = prefix + '_' + simpleName + "PortType_" + prefix + '_' + simpleName + "Port";
}
//---------------------------------------------------------------------------
// Public methods.
// --------------------------------------------------------------------------
/**
* Generate the JavaScript code for declaring and setting the proxy variable.
*/
public void generateJavaScript(PrintWriter pw)
{
pw.println();
pw.println("<!-- the object to talk to the " + referenceName + " Web service. -->");
pw.println("var " + referenceName + ";");
pw.println("<!-- retrieve the JavaScript proxy client for the " + referenceName + " Web service. -->");
pw.println("includeJs(\"" + uri + "?js\",");
pw.println(" function() {");
pw.println(" " + referenceName + " = new " + apacheCxfProxyName + "()");
pw.println(" }");
pw.println(')');
}
}
......@@ -27,18 +27,32 @@
package org.ow2.frascati.implementation.widget;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.Servlet;
import org.eclipse.stp.sca.Binding;
import org.eclipse.stp.sca.Component;
import org.eclipse.stp.sca.ComponentService;
import org.eclipse.stp.sca.ComponentReference;
import org.eclipse.stp.sca.Interface;
import org.eclipse.stp.sca.JavaInterface;
import org.eclipse.stp.sca.ScaFactory;
import org.eclipse.stp.sca.PropertyValue;
import org.eclipse.stp.sca.WebServiceBinding;
import org.oasisopen.sca.annotation.Property;
import org.oasisopen.sca.annotation.Reference;
import org.ow2.frascati.assembly.factory.api.ProcessingContext;
import org.ow2.frascati.assembly.factory.api.ProcessorException;
import org.ow2.frascati.assembly.factory.processor.AbstractComponentFactoryBasedImplementationProcessor;
import org.ow2.frascati.assembly.factory.processor.AbstractInterfaceProcessor;
import org.ow2.frascati.component.factory.api.MembraneGeneration;
import org.ow2.frascati.metamodel.web.WidgetImplementation;
import org.ow2.frascati.metamodel.web.WebPackage;
import org.ow2.frascati.tinfi.api.control.SCAPropertyController;
......@@ -56,6 +70,18 @@ public class FrascatiImplementationWidgetProcessor
// Internal state.
// --------------------------------------------------------------------------
/**
* Package where content classes are generated.
*/
@Property(name = "package")
private String packageGeneration;
/**
* Reference to Juliac configuration.
*/
@Reference(name = "membrane-generation")
private MembraneGeneration membraneGeneration;
//---------------------------------------------------------------------------
// Internal methods.
// --------------------------------------------------------------------------
......@@ -80,16 +106,25 @@ public class FrascatiImplementationWidgetProcessor
throws ProcessorException
{
String location = widgetImplementation.getLocation();
checkAttributeMustBeSet(widgetImplementation, "location", location, processingContext);
boolean checkDefaultInClassLoader = true;
// Check that location is present in the class path.
if(!isNullOrEmpty(location) && processingContext.getClassLoader().getResourceAsStream(location) == null) {
// Location not found.
error(processingContext, widgetImplementation, "Location '" + location + "' not found");
checkDefaultInClassLoader = false;
}
// TODO check widgetImplementation.default
String default_ = widgetImplementation.getDefault();
// checkAttributeMustBeSet(widgetImplementation, "default", default_, processingContext);
// Check that default is present in the class path.
if(checkDefaultInClassLoader && !isNullOrEmpty(default_) && processingContext.getClassLoader().getResourceAsStream(location + '/' + default_) == null) {
// Default not found.
error(processingContext, widgetImplementation, "Default '" + default_ + "' not found");
}
// Get the enclosing SCA component.
Component component = getParent(widgetImplementation, Component.class);
......@@ -136,8 +171,84 @@ public class FrascatiImplementationWidgetProcessor
protected final void doGenerate(WidgetImplementation widgetImplementation, ProcessingContext processingContext)
throws ProcessorException
{
// Get the parent component.
Component component = getParent(widgetImplementation, Component.class);
// Name of the content class.
String contentFullClassName = null;
if(component.getProperty().size() == 0 && component.getReference().size() == 0) {
// if no property and no reference then use default ImplementationVelocity class.
contentFullClassName = ImplementationWidgetComponent.class.getName();
} else {
String basename = widgetImplementation.getLocation() + widgetImplementation.getDefault();
int hashCode = basename.hashCode();
if(hashCode < 0) {
hashCode = -hashCode;
}
// if some property or some reference then generate an ImplementationWidgetComponent class.
String contentClassName = ImplementationWidgetComponent.class.getSimpleName() + hashCode;
// Add the package to the content class name.
contentFullClassName = this.packageGeneration + '.' + contentClassName;
try {
processingContext.loadClass(contentFullClassName);
} catch(ClassNotFoundException cnfe) {
// If the class can not be found then generate it.
log.info(packageGeneration + '.' + contentClassName);
// Create the output directory for generation.
String outputDirectory = this.membraneGeneration.getOutputDirectory() + "/generated-frascati-sources";
// Add the output directory to the Java compilation process.
this.membraneGeneration.addJavaSource(outputDirectory);
try { // Generate a sub class of ImplementationVelocity declaring SCA references and properties.
File packageDirectory = new File(outputDirectory + '/'
+ packageGeneration.replace('.', '/'));
packageDirectory.mkdirs();
PrintStream file = new PrintStream(new FileOutputStream(new File(
packageDirectory, contentClassName + ".java")));
file.println("package " + packageGeneration + ";\n");
file.println("public class " + contentClassName + " extends "
+ ImplementationWidgetComponent.class.getName());
file.println("{");
int index = 0;
for (PropertyValue propertyValue : component.getProperty()) {
// Get the property value and class.
Object propertyValueObject = processingContext.getData(propertyValue, Object.class);
Class<?> propertyValueClass = (propertyValueObject != null) ? propertyValueObject
.getClass() : String.class;
file.println(" @" + Property.class.getName() + "(name = \""
+ propertyValue.getName() + "\")");
file.println(" protected " + propertyValueClass.getName()
+ " property" + index + ";");
index++;
}
index = 0;
for (ComponentReference componentReference : component.getReference()) {
file.println(" @" + Reference.class.getName() + "(name = \""
+ componentReference.getName() + "\")");
file.println(" protected Object reference" + index + ";");
index++;
}
file.println("}");
file.flush();
file.close();
} catch(FileNotFoundException fnfe) {
severe(new ProcessorException(widgetImplementation, fnfe));
}
}
}
// Generate a FraSCAti SCA primitive component.
generateScaPrimitiveComponent(widgetImplementation, processingContext, ImplementationWidgetComponent.class.getName());
generateScaPrimitiveComponent(widgetImplementation, processingContext, contentFullClassName);
// Store the content class name to retrieve it from next doInstantiate method.
processingContext.putData(widgetImplementation, String.class, contentFullClassName);
}
/**
......@@ -149,7 +260,8 @@ public class FrascatiImplementationWidgetProcessor
{
// Instantiate a FraSCAti SCA primitive component.
org.objectweb.fractal.api.Component component =
instantiateScaPrimitiveComponent(widgetImplementation, processingContext, ImplementationWidgetComponent.class.getName());
instantiateScaPrimitiveComponent(widgetImplementation, processingContext,
processingContext.getData(widgetImplementation, String.class));
// Retrieve the SCA property controller of this Fractal component.
SCAPropertyController propertyController = (SCAPropertyController)getFractalInterface(component, SCAPropertyController.NAME);
......@@ -164,6 +276,44 @@ public class FrascatiImplementationWidgetProcessor
propertyController.setValue("default", widgetImplementation.getDefault());
}
/**
* @see org.ow2.frascati.assembly.factory.processor.api.Processor#complete(ElementType, ProcessingContext)
*/
@Override
protected final void doComplete(WidgetImplementation widgetImplementation, ProcessingContext processingContext)
throws ProcessorException
{
// Compute the binding infos.
List<BindingInfo> bindingInfos = new ArrayList<BindingInfo>();
// Traverse all references of the enclosing component of this widget implementation.
for(ComponentReference reference : getParent(widgetImplementation, Component.class).getReference()) {
// for each reference, traverse all references of the target service.
for(Binding binding : reference.getTarget2().getBinding()) {
// when binding is a Web Service
if(binding instanceof WebServiceBinding) {
WebServiceBinding wsb = (WebServiceBinding)binding;
bindingInfos.add(
new BindingInfo(reference.getName(),
AbstractInterfaceProcessor.getClass(reference.getInterface(), processingContext),
wsb.getUri()
)
);
}
}
}
// Retrieve the FraSCAti SCA primitive component.
org.objectweb.fractal.api.Component component =
processingContext.getData(widgetImplementation, org.objectweb.fractal.api.Component.class);
// Retrieve the SCA property controller of this Fractal component.
SCAPropertyController propertyController = (SCAPropertyController)getFractalInterface(component, SCAPropertyController.NAME);
// Set the bindingInfos property.
propertyController.setValue("bindingInfos", bindingInfos);
}
//---------------------------------------------------------------------------
// Public methods.
// --------------------------------------------------------------------------
......
......@@ -29,6 +29,8 @@ package org.ow2.frascati.implementation.widget;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.List;
import java.util.Properties;
import javax.servlet.Servlet;
......@@ -37,6 +39,7 @@ import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.osoa.sca.annotations.ComponentName;
import org.osoa.sca.annotations.Property;
import org.osoa.sca.annotations.Scope;
import org.osoa.sca.annotations.Service;
......@@ -93,6 +96,18 @@ public class ImplementationWidgetComponent
@Property(name = "default")
private String defaultResource;
/**
* Binding infos.
*/
@Property(name = "bindingInfos")
private List<BindingInfo> bindingInfos;
/**
* The name of the enclosing SCA component.
*/
@ComponentName
private String componentName;
//---------------------------------------------------------------------------
// Internal methods.
// --------------------------------------------------------------------------
......@@ -107,10 +122,14 @@ public class ImplementationWidgetComponent
// The requested resource.
String pathInfo = request.getPathInfo();
if(pathInfo == null) {
pathInfo = "";
pathInfo = defaultResource;
}
// When the JavaScript for the enclosing SCA component is requested then generate it.
if(('/' + componentName + ".js").equals(pathInfo)) {
generateJavaScriptForEnclosingComponent(response);
return;
}
int idx = pathInfo.lastIndexOf('.');
String extension = (idx != -1) ? pathInfo.substring(idx) : "";
// Search the requested resource into the class loader.
InputStream is = this.classloader.getResourceAsStream(this.location + pathInfo);
......@@ -123,6 +142,10 @@ public class ImplementationWidgetComponent
// Requested resource found.
response.setStatus(HttpServletResponse.SC_OK);
// set the content type.
int idx = pathInfo.lastIndexOf('.');
String extension = (idx != -1) ? pathInfo.substring(idx) : "";
String mimeType = extensions2mimeTypes.getProperty(extension);
if(mimeType == null) {
mimeType = "text/plain";
......@@ -133,6 +156,27 @@ public class ImplementationWidgetComponent
Stream.copy(is, response.getOutputStream());
}
/**
* Generate the JavaScript for the enclosing SCA component.
*/
protected void generateJavaScriptForEnclosingComponent(HttpServletResponse response)
throws IOException
{
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("text/javascript");
PrintWriter pw = response.getWriter();
pw.println("function includeJs(jsFilePath, callback) {");
pw.println(" var js = document.createElement(\"script\");");
pw.println(" js.type = \"text/javascript\";");
pw.println(" js.onload = callback");
pw.println(" js.src = jsFilePath;");
pw.println(" document.head.appendChild(js);");
pw.println('}');
for(BindingInfo bi : this.bindingInfos) {
bi.generateJavaScript(pw);
}
}
//---------------------------------------------------------------------------
// Public methods.
// --------------------------------------------------------------------------
......
......@@ -28,6 +28,10 @@
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0" xmlns:af="org/ow2/frascati/assembly/factory" name="org.ow2.frascati.assembly.factory.AssemblyFactory">
<component constrainingType="af:ComponentFactoryBasedImplementationProcessorType" name="frascati-implementation-widget">
<implementation.java class="org.ow2.frascati.implementation.widget.FrascatiImplementationWidgetProcessor"/>
<property name="package">generated.frascati</property>
<reference name="membrane-generation">
<interface.java interface="org.ow2.frascati.component.factory.api.MembraneGeneration"/>
</reference>
</component>
<wire source="sca-implementation/implementations" target="frascati-implementation-widget/implementation-processor"/>
</composite>
......@@ -66,9 +66,8 @@ public class FraSCAtiTest {
compositeManager.processComposite(new QName("CheckingErrorsWarnings"), processingContext);
} catch(ManagerException me) {
// Let's note that the following number of errors is conform to comments in file 'CheckingErrorsWarnings.composite'
assertEquals("The number of checking errors", 5, processingContext.getErrors());
// Let's note that the file 'CheckingErrorsWarnings.composite' produces 2 warnings,
// one warning is also produced by the OW2 FraSCAti Parser (EMF diagnostics).
assertEquals("The number of checking errors", 6, processingContext.getErrors());
// Let's note that the file 'CheckingErrorsWarnings.composite' produces 2 warnings.
assertEquals("The number of checking warnings", 2, processingContext.getWarnings());
}
}
......
......@@ -36,7 +36,8 @@
</component>
<component name="c2">
<web:implementation.widget location="contents/"/>
<!-- following is an error: Default 'foo' not found. -->
<web:implementation.widget location="contents/" default="foo"/>
<!-- following is an error: <implementation.widget> can't have more than one SCA service. -->
<service name="s1">
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment