Commit d090d86d authored by seinturier's avatar seinturier

Intent and policy set controller.

Associated example in advanced/helloworld-with-intent.
parent 4c902a52
......@@ -74,6 +74,7 @@ In addition the examples/advanced directory contains some advanced samples. See
the README.txt in the corresponding directories to obtain more information about
these samples.
- helloworld-bin: binary components (compiled classes) with Tinfi
- helloworld-with-intent: the Hello World example with policy sets
3. Compiling and installing Tinfi
......@@ -185,4 +186,4 @@ To run the conformance tests, type:
For any question concerning Tinfi, please contact
Lionel.Seinturier@univ-lille1.fr
Date of creation of this file: June 24, 2007.
Last modified: May 19, 2008.
Last modified: May 22, 2008.
Tinfi 0.3
---------
* new controller for handling policy sets and intents
Tinfi 0.2.1
-----------
* org.scorware.tinfi.Tinfi is a full-fledged Fractal provider class
......
......@@ -31,10 +31,10 @@ import org.objectweb.fractal.adl.juliac.MembraneDesc;
import org.objectweb.fractal.adl.juliac.proxy.InterceptorSourceCodeGenerator;
import org.objectweb.fractal.adl.juliac.ucf.UnifiedClass;
import org.objectweb.fractal.adl.juliac.ucf.UnifiedMethod;
import org.objectweb.fractal.adl.juliac.visit.BlockSourceCodeVisitor;
import org.objectweb.fractal.adl.juliac.visit.ClassSourceCodeVisitor;
import org.objectweb.fractal.adl.juliac.visit.MethodSourceCodeVisitor;
import org.objectweb.fractal.api.type.InterfaceType;
import org.objectweb.fractal.julia.factory.ChainedInstantiationException;
import org.scorware.tinfi.TinfiRuntimeException;
import org.scorware.tinfi.control.intent.IntentJoinPoint;
import org.scorware.tinfi.control.intent.IntentJoinPointImpl;
......@@ -114,45 +114,6 @@ extends InterceptorSourceCodeGenerator {
@Override
protected void generateMethodInitFcController( MethodSourceCodeVisitor mv, UnifiedClass proxycl ) {
/*
* If needed initialize the array constant referencing the methods
* implemented by the proxy class. The elements from this array are used
* when instanciating {@link IntentJoinPointImpl} instances.
*/
StringBuffer expression = new StringBuffer("new java.lang.reflect.Method[]{");
String proxyclname = proxycl.getName();
UnifiedMethod[] proxymethods = proxycl.getMethods();
for (int i = 0; i <proxymethods.length; i++) {
if(i!=0) { expression.append(','); }
UnifiedMethod proxym = proxymethods[i];
String proxymname = proxym.getName();
UnifiedClass[] paramtypes = proxym.getParameterTypes();
expression.append(proxyclname+".class.getMethod(\"");
expression.append(proxymname+"\"");
for (UnifiedClass paramtype : paramtypes) {
expression.append(',');
String paramtypename = paramtype.getName();
expression.append(paramtypename+".class");
}
expression.append(")");
}
expression.append("}");
mv.visitln(" try {");
mv.visitln(" if( METHODS == null ) {");
mv.visit (" METHODS = ");
mv.visit (expression.toString());
mv.visitln(";");
mv.visitln(" }");
mv.visitln(" }");
mv.visitln(" catch( Exception e ) {");
mv.visit (" throw new ");
mv.visit (ChainedInstantiationException.class.getName());
mv.visitln("(e,null,\"\");");
mv.visitln(" }");
}
@Override
......@@ -218,56 +179,65 @@ extends InterceptorSourceCodeGenerator {
mv.visit (" ");
mv.visit (SCAIntentController.class.getName());
mv.visitln(" ic = getIntentController();");
mv.visitln(" try {");
UnifiedClass rtype = proxym.getReturnType();
if( rtype.getName().equals("void") ) {
mv.visitln(" ic.handle(ijp);");
}
else {
mv.visitln(" Object ret = ic.handle(ijp);");
mv.visit (" return ");
if( isPrimitive(rtype) ) {
String boxedClassName = getBoxedClassName(rtype);
mv.visit ("((");
mv.visit (boxedClassName);
mv.visit (")ret).");
mv.visit (rtype.getName());
mv.visitln("Value();");
}
else {
mv.visit ("(");
mv.visit (rtype.getName());
mv.visitln(")ret;");
}
}
mv.visitln(" }");
mv.visitln(" catch( Exception e ) {");
mv.visit (" throw new ");
mv.visit (TinfiRuntimeException.class.getName());
mv.visitln("(e);");
mv.visitln(" }");
mv.visitln(" ic.before(ijp);");
/*
* Hack to hide the call to the delegate which is indeed performed by
* the intent controller.
*
* TODO AbstractProxySourceCodeGenerator#generateProxyMethodBody should be refactored
* to allow for overriding the call to the delefate instance
*/
mv.visitln(" /*");
// Begin of try/finally block
mv.visitln(" try {");
}
@Override
public void generateProxyMethodBodyFinallyCode(
MethodSourceCodeVisitor mv, UnifiedClass proxycl, UnifiedMethod proxym ) {
// End of try/finally block
mv.visitln(" }");
mv.visitln(" finally {");
mv.visitln(" ic.after(ijp);");
mv.visitln(" }");
}
@Override
public void generateStaticParts( ClassSourceCodeVisitor cv, UnifiedClass proxycl ) {
/*
* Hack to hide the call to the delegate which is indeed performed by
* the intent controller.
* Initialize the array constant referencing the methods
* implemented by the proxy class. The elements from this array are used
* when instanciating {@link IntentJoinPointImpl} instances.
*/
mv.visitln(" */");
StringBuffer expression = new StringBuffer("new java.lang.reflect.Method[]{");
String proxyclname = proxycl.getName();
UnifiedMethod[] proxymethods = proxycl.getMethods();
for (int i = 0; i <proxymethods.length; i++) {
if(i!=0) { expression.append(','); }
UnifiedMethod proxym = proxymethods[i];
String proxymname = proxym.getName();
UnifiedClass[] paramtypes = proxym.getParameterTypes();
expression.append(proxyclname+".class.getMethod(\"");
expression.append(proxymname+"\"");
for (UnifiedClass paramtype : paramtypes) {
expression.append(',');
String paramtypename = paramtype.getName();
expression.append(paramtypename+".class");
}
expression.append(")");
}
expression.append("}");
BlockSourceCodeVisitor mv = cv.visitStaticPart();
mv.visitBegin();
mv.visitln(" try {");
mv.visit (" METHODS = ");
mv.visit (expression.toString());
mv.visitln(";");
mv.visitln(" }");
mv.visitln(" catch( Exception e ) {");
mv.visit (" throw new RuntimeException(e);");
mv.visitln(" }");
mv.visitEnd();
}
// -----------------------------------------------------------------------
// Implementation specific
......
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.scorware.tinfi</groupId>
<artifactId>frascati-tinfi-parent</artifactId>
<version>0.3-SNAPSHOT</version>
</parent>
<groupId>org.scorware.tinfi.examples</groupId>
<artifactId>frascati-tinfi-helloworld-with-intent</artifactId>
<packaging>jar</packaging>
<name>Tinfi HelloWorld example with policy sets</name>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.4</version>
</dependency>
<dependency>
<groupId>org.scorware.tinfi</groupId>
<artifactId>frascati-tinfi-compiler</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.scorware.tinfi</groupId>
<artifactId>frascati-tinfi-mixins</artifactId>
<version>${project.version}</version>
<classifier>sources</classifier>
</dependency>
<dependency>
<groupId>org.objectweb.fractal.julia</groupId>
<artifactId>julia-mixins</artifactId>
<version>${julia.version}</version>
<classifier>sources</classifier>
</dependency>
</dependencies>
<build>
<plugins>
<!-- ==================================== -->
<!-- Generate and compile the application -->
<!-- ==================================== -->
<plugin>
<groupId>org.objectweb.fractal.fractaladl.juliac</groupId>
<artifactId>maven-juliac-plugin</artifactId>
<version>${juliac.version}</version>
<executions>
<execution>
<id>juliac-compile</id>
<phase>generate-sources</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<configuration>
<srcs>src/main/java</srcs>
<opt>org.scorware.tinfi.juliac.FCOOCtrlSourceCodeGenerator</opt>
<mixins>org.scorware.tinfi:frascati-tinfi-mixins:${project.version}:sources org.objectweb.fractal.julia:julia-mixins:${julia.version}:sources</mixins>
<types>example.hw.HelloWorld</types>
<sysargs>julia.config=tinfi.cfg</sysargs>
<!-- verbose>true</verbose -->
</configuration>
</plugin>
</plugins>
</build>
</project>
package example.hw;
import org.osoa.sca.annotations.Init;
import org.osoa.sca.annotations.Reference;
public class ClientImpl implements Runnable {
public ClientImpl() {
Console.println("CLIENT created");
}
@Init
public void init() {
Console.println("CLIENT initialized");
}
public void run() {
s.print("hello world");
}
@Reference
public Service s;
}
\ No newline at end of file
package example.hw;
import java.io.PrintStream;
public class Console {
public static PrintStream ps = System.err;
public static void println( String msg ) {
ps.println(msg);
}
}
package example.hw;
import org.osoa.sca.annotations.PolicySets;
import org.osoa.sca.annotations.Property;
@PolicySets("debug1")
public class ServerImpl implements Service {
private String header = "->";
private int count = 1;
public ServerImpl() {
Console.println("SERVER created");
}
@PolicySets("debug2")
public void print(final String msg) {
Console.println("Server: begin printing...");
for (int i = 0 ; i < (count) ; ++i) {
Console.println(((header) + msg));
}
Console.println("Server: print done.");
}
public String getHeader() {
return header;
}
@Property
public void setHeader(final String header) {
this.header = header;
}
public int getCount() {
return count;
}
@Property
public void setCount(final int count) {
this.count = count;
}
}
\ No newline at end of file
package example.hw;
public interface Service {
void print(String msg);
}
\ No newline at end of file
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE definition PUBLIC "-//objectweb.org//DTD Fractal ADL 2.0//EN" "classpath://org/objectweb/fractal/adl/xml/standard.dtd">
<definition name="example.hw.HelloWorld" >
<interface name="r" signature="java.lang.Runnable" role="server" />
<component name="client">
<interface name="r" signature="java.lang.Runnable" role="server" />
<interface name="s" signature="example.hw.Service" role="client" />
<content class="example.hw.ClientImpl"/>
<controller desc="scaPrimitive" />
</component>
<component name="server">
<interface name="s" signature="example.hw.Service" role="server" cardinality="singleton" contingency="mandatory"/>
<content class="example.hw.ServerImpl"/>
<controller desc="scaPrimitive"/>
</component>
<binding client="this.r" server="client.r" />
<binding client="client.s" server="server.s" />
</definition>
/***
* Tinfi
* Copyright (C) 2008 INRIA, USTL
*
* 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: Lionel.Seinturier@univ-lille1.fr
*
* Author: Lionel Seinturier
*/
package example.hw;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Method;
import org.junit.Assert;
import org.junit.Test;
import org.objectweb.fractal.api.Component;
import org.objectweb.fractal.api.NoSuchInterfaceException;
import org.objectweb.fractal.api.factory.Factory;
import org.objectweb.fractal.api.factory.InstantiationException;
import org.objectweb.fractal.util.Fractal;
import org.osoa.sca.annotations.PolicySets;
import org.scorware.tinfi.control.content.ContentClassMetaData;
import org.scorware.tinfi.control.content.IllegalContentClassMetaData;
import org.scorware.tinfi.control.intent.Handler;
import org.scorware.tinfi.control.intent.IntentJoinPoint;
import org.scorware.tinfi.control.intent.SCAIntentController;
/**
* Automate the launching of the HelloWorld example and check that the example
* runs as expected.
*
* @author Lionel Seinturier <Lionel.Seinturier@univ-lille1.fr>
* @since 0.3
*/
public class HelloWorldTestCase {
@Test
public void helloWorld()
throws
IOException, InstantiationException, NoSuchInterfaceException,
ClassNotFoundException, java.lang.InstantiationException,
IllegalAccessException {
/*
* Use the Console class to direct the output of the example to a
* temporary file.
*/
File tmp = File.createTempFile("helloworld-with-intent-",".txt");
PrintStream ps = new PrintStream(tmp);
Console.ps = ps;
/*
* Instanciate the HelloWorld composite.
*/
@SuppressWarnings("unchecked")
Class<Factory> cl = (Class<Factory>) Class.forName("example.hw.HelloWorld");
Factory factory = cl.newInstance();
Component root = factory.newFcInstance();
Component[] subs = Fractal.getContentController(root).getFcSubComponents();
Component server = subs[1];
/*
* Register intent handlers with the server component.
*/
SCAIntentController ic = (SCAIntentController) server.getFcInterface(SCAIntentController.NAME);
ic.addHandler( new PolicySetDebug1Handler() );
ic.addHandler( new PolicySetDebug2Handler() );
/*
* Run the application.
*/
Runnable r = (Runnable) root.getFcInterface("r");
r.run();
/*
* Close the console.
*/
ps.close();
/*
* Dump the content of the temporay file to the console for visual
* check.
*/
FileReader fr = new FileReader(tmp);
int b;
while( (b=fr.read()) != -1 ) {
char c = (char) b;
System.err.print(c);
}
fr.close();
File tmpExpected = File.createTempFile("helloworld-with-intent-",".txt");
ps = new PrintStream(tmpExpected);
for (String expected : expecteds) {
ps.println(expected);
}
ps.close();
/*
* Compare the output with the expected result.
*/
fr = new FileReader(tmp);
FileReader frExpected = new FileReader(tmpExpected);
int i=0,line=1,col=1;
while( (b=fr.read()) != -1 ) {
char c = (char) b;
char e = (char) frExpected.read();
if( c != e ) {
String msg = "Unexpected character at line "+line+", column "+col;
System.err.println();
System.err.println("Expected output is: ");
for (String expected : expecteds) {
System.err.println(expected);
}
Assert.fail(msg);
}
i++;
if( c == '\n' ) {
line++;
col=1;
}
else {
col++;
}
}
frExpected.close();
fr.close();
/*
* Delete temporary files.
*/
tmp.delete();
tmpExpected.delete();
}
final static private String[] expecteds =
new String[]{
"CLIENT created",
"CLIENT initialized",
"SERVER created",
"<< debug1: before",
"<< debug2: before",
"Server: begin printing...",
"->hello world",
"Server: print done.",
"<< debug2: after",
"<< debug1: after"
};
/**
* A handler for the policy set debug1.
* This handler applies on component classes annotated with @{@link
* PolicySets}("debug1").
*
* @author Lionel Seinturier <Lionel.Seinturier@univ-lille1.fr>
* @since 0.3
*/
public static class PolicySetDebug1Handler implements Handler {
@Override
public void before( IntentJoinPoint ijp ) {
if( applies(ijp) ) {
Console.println("<< debug1: before");
}
}
public void after( IntentJoinPoint ijp ) {
if( applies(ijp) ) {
Console.println("<< debug1: after");
}
}
private boolean applies( IntentJoinPoint ijp ) {
Object intentTarget = ijp.getIntentTarget();
Class<?> intentClass = intentTarget.getClass();
ContentClassMetaData ccmd = null;
try {
ccmd = ContentClassMetaData.get(intentClass.getName());
}
catch (IllegalContentClassMetaData e) {
throw new RuntimeException(e);
}
PolicySets pss = ccmd.getAnnotation(PolicySets.class);
if( pss != null ) {
String[] values = pss.value();
for (String value : values) {
if( value.equals("debug1") ) {
return true;
}
}
}
return false;
}
}
/**
* A handler for the policy set debug2.
* This handler applies on component classes annotated with @{@link
* PolicySets}("debug2").
*
* @author Lionel Seinturier <Lionel.Seinturier@univ-lille1.fr>
* @since 0.3
*/
public static class PolicySetDebug2Handler implements Handler {
@Override
public void before( IntentJoinPoint ijp ) {
if( applies(ijp) ) {
Console.println("<< debug2: before");
}
}
public void after( IntentJoinPoint ijp ) {
if( applies(ijp) ) {
Console.println("<< debug2: after");
}
}
private boolean applies( IntentJoinPoint ijp ) {
Object intentTarget = ijp.getIntentTarget();
Class<?> intentClass = intentTarget.getClass();
String intentMethodName = ijp.getIntentMethod().getName();
ContentClassMetaData ccmd = null;
try {
ccmd = ContentClassMetaData.get(intentClass.getName());
}
catch (IllegalContentClassMetaData e) {
throw new RuntimeException(e);
}
Method[] methods = ccmd.getAllAnnotatedMethods(PolicySets.class);
for (Method method : methods) {
if( method.getName().equals(intentMethodName) ) {
PolicySets pss = method.getAnnotation(PolicySets.class);
if( pss != null ) {
String[] values = pss.value();
for (String value : values) {
if( value.equals("debug2") ) {
return true;
}
}
}
}
}
return false;
}
}
}
......@@ -83,17 +83,34 @@ implements Controller, SCAIntentController {
}
/**
* Handle the intent policy associated with the specified intent join point.
* Handle the before part of the intent policy associated with the specified
* intent join point.
*
* @param ijp the intent join point
* @return the result of the intent policy
*/
public Object handle( IntentJoinPoint ijp ) throws Exception {
ijp.setHandlers(handlers);
Object ret = ijp.invokeNext();
return ret;
public void before( IntentJoinPoint ijp ) {
if( handlers != null ) {
ijp.setHandlers(handlers);