/*************************************************************************** * Copyright (C) by Claudio Guidi * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program 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 General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * For details about the authors of this software, see the AUTHORS file. * ***************************************************************************/ package joliex.meta; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import jolie.CommandLineException; import jolie.CommandLineParser; import jolie.lang.NativeType; import jolie.lang.parse.ParserException; import jolie.lang.parse.ast.InputPortInfo; import jolie.lang.parse.ast.InterfaceDefinition; import jolie.lang.parse.ast.OneWayOperationDeclaration; import jolie.lang.parse.ast.OperationDeclaration; import jolie.lang.parse.ast.OutputPortInfo; import jolie.lang.parse.ast.PortInfo; import jolie.lang.parse.ast.Program; import jolie.lang.parse.ast.RequestResponseOperationDeclaration; import jolie.lang.parse.ast.types.TypeDefinition; import jolie.lang.parse.ast.types.TypeDefinitionLink; import jolie.lang.parse.ast.types.TypeInlineDefinition; import jolie.lang.parse.util.ParsingUtils; import jolie.lang.parse.util.ProgramInspector; import jolie.runtime.JavaService; import jolie.runtime.Value; import jolie.runtime.ValueVector; import jolie.runtime.embedding.RequestResponse; import jolie.util.Range; /** * * @author claudio guidi */ public class MetaJolie extends JavaService { private int MAX_CARD = 2147483647; private boolean is_generalType( String type ) { // standard types are not inserted. TO BE IMPROVED boolean response = false; if ( type.equals("Date") ) { response = true; } else if ( type.equals("String") ) { response = true; } else if ( type.equals("Integer") ) { response = true; } else if ( type.equals("Void") ) { response = true; } else if ( type.equals("__Role") ) { response = true; } return response; } private Value getNativeType( NativeType type ) { Value response = Value.create(); if ( type == NativeType.ANY ) { response.getFirstChild("any_type").setValue( true ); } else if ( type == NativeType.STRING ) { response.getFirstChild("string_type").setValue( true ); } else if ( type == NativeType.DOUBLE ) { response.getFirstChild("double_type").setValue( true ); } else if ( type == NativeType.INT ) { response.getFirstChild("int_type").setValue( true ); } else if ( type == NativeType.VOID ) { response.getFirstChild("void_type").setValue( true ); } else if ( type == NativeType.BOOL ) { response.getFirstChild("bool_type").setValue( true ); } else if ( type == NativeType.LONG ) { response.getFirstChild( "long_type").setValue( true ); } // type undefined? return response; } private boolean isNativeType ( String type ) { if ( type.equals("any") || type.equals("string") || type.equals("double") || type.equals("int") || type.equals("void")) { return true; } else { return false; } } private Value addCardinality( Range range ) { Value response = Value.create(); response.getFirstChild("min").setValue( range.min() ); if ( range.max() == MAX_CARD ) { response.getFirstChild("infinite").setValue(1); } else { response.getFirstChild("max").setValue( range.max() ); } return response; } private Value addTypeInLine( ArrayList<TypeDefinition> types, ValueVector types_vector, Value name, TypeDefinition typedef ) { Value response = Value.create(); response.getFirstChild("name").getFirstChild( "name").setValue( typedef.id() ); // not useful, inserted for respecting Type if ( typedef instanceof TypeDefinitionLink ) { response.getFirstChild("root_type").getFirstChild("link").setValue( ((TypeDefinitionLink) typedef ).linkedTypeName()); insertType( types, types_vector, name, ((TypeDefinitionLink) typedef ).linkedType() ); } else { TypeInlineDefinition td = ( TypeInlineDefinition ) typedef; response.getFirstChild("root_type").deepCopy( getNativeType( typedef.nativeType() )); if ( td.hasSubTypes() ) { for ( Entry<String,TypeDefinition> entry : td.subTypes() ) { response.getChildren("sub_type").add( addSubType( types, types_vector, name, entry.getValue() ) ); } } } return response; } private Value addSubType( ArrayList<TypeDefinition> types, ValueVector types_vector, Value name, TypeDefinition type ) { Value response = Value.create(); response.getFirstChild("name").setValue( type.id() ); response.getFirstChild("cardinality").deepCopy( addCardinality(type.cardinality())); if ( type instanceof TypeDefinitionLink ) { response.getFirstChild("type_link").deepCopy( setName(name)); response.getFirstChild( "type_link").getFirstChild( "name").setValue( ((TypeDefinitionLink) type).linkedTypeName() ); if ( !is_generalType( ((TypeDefinitionLink) type).linkedTypeName() ) ) { insertType( types, types_vector, name, ((TypeDefinitionLink) type ).linkedType() ); } } else { response.getFirstChild("type_inline").deepCopy( addTypeInLine( types, types_vector, name, type )); } return response; } private void insertType( ArrayList<TypeDefinition> types, ValueVector types_vector, Value name, TypeDefinition typedef ) { if ( !types.contains( typedef )) { Value type = Value.create(); if ( typedef instanceof TypeDefinitionLink ) { if ( !is_generalType( typedef.id() ) ) { type.getFirstChild("name").deepCopy( setName( name )); type.getFirstChild( "name").getFirstChild( "name").setValue( typedef.id() ); type.getFirstChild("root_type").getFirstChild("link").getFirstChild("name").setValue( ((TypeDefinitionLink) typedef ).linkedTypeName()); insertType( types, types_vector, name, ((TypeDefinitionLink) typedef ).linkedType() ); } } else { if ( !is_generalType( typedef.id() ) ) { TypeInlineDefinition td = ( TypeInlineDefinition ) typedef; type.getFirstChild("name").deepCopy( setName( name )); type.getFirstChild( "name").getFirstChild( "name").setValue( td.id() ); type.getFirstChild("root_type").deepCopy( getNativeType( td.nativeType() )); if ( td.hasSubTypes() ) { int subtype_counter = 0; for ( Entry<String,TypeDefinition> entry : td.subTypes() ) { type.getChildren("sub_type").get( subtype_counter ).deepCopy( addSubType( types, types_vector, name, entry.getValue() ) ); subtype_counter++; } } } } types_vector.add( type ); } } private Value getSubType( TypeDefinition type, Value name ) { Value response = Value.create(); response.getFirstChild("name").setValue( type.id() ); response.getFirstChild("cardinality").deepCopy( addCardinality(type.cardinality())); if ( type instanceof TypeDefinitionLink ) { response.getFirstChild("type_link").deepCopy( setName( name )); response.getFirstChild( "type_link").getFirstChild("name").setValue( ((TypeDefinitionLink) type).linkedTypeName() ); } else { response.getFirstChild("type_inline").deepCopy( getType( type, name )); } return response; } private Value getType( TypeDefinition typedef, Value name ) { Value type = Value.create(); type.getFirstChild("name").deepCopy( setName( name )); type.getFirstChild("name").getFirstChild( "name").setValue( typedef.id() ); if ( typedef instanceof TypeDefinitionLink ) { type.getFirstChild("root_type").getFirstChild("link").getFirstChild("name").setValue(((TypeDefinitionLink) typedef ).linkedTypeName()); if ( name.getFirstChild( "domain").isDefined() ) { type.getFirstChild("root_type").getFirstChild("link").getFirstChild("domain").setValue( name.getFirstChild("domain").strValue() ); } } else { TypeInlineDefinition td = ( TypeInlineDefinition ) typedef; type.getFirstChild("root_type").deepCopy( getNativeType( td.nativeType() )); if ( td.hasSubTypes() ) { int subtype_counter = 0; for ( Entry<String,TypeDefinition> entry : td.subTypes() ) { type.getChildren("sub_type").get( subtype_counter ).deepCopy( getSubType( entry.getValue(), name ) ); subtype_counter++; } } } return type; } private List<TypeDefinition> addType( List<TypeDefinition> types, TypeDefinition typedef ) { if ( !types.contains( typedef )) { types.add( typedef ); if ( typedef instanceof TypeDefinitionLink ) { addType( types, ((TypeDefinitionLink) typedef ).linkedType() ); } else { TypeInlineDefinition td = ( TypeInlineDefinition ) typedef; if ( td.hasSubTypes() ) { for ( Entry<String,TypeDefinition> entry : td.subTypes() ) { addType( types, entry.getValue() ); } } } } return types; } private Value getInterface( InterfaceDefinition intf, Value name, List<TypeDefinition> types ) { Value response = Value.create(); // setting the name response.getFirstChild("name").deepCopy( setName( name ) ); response.getFirstChild( "name" ).getFirstChild( "name" ).setValue( intf.name() ); ValueVector operations = response.getChildren("operations"); // scans operations and types Map< String , OperationDeclaration > operationMap = intf.operationsMap(); for ( Entry< String , OperationDeclaration > operationEntry:operationMap.entrySet() ) { Value current_operation = Value.create(); if ( operationEntry.getValue() instanceof OneWayOperationDeclaration ) { OneWayOperationDeclaration oneWayOperation = ( OneWayOperationDeclaration)operationEntry.getValue(); current_operation.getFirstChild( "operation_name").setValue( oneWayOperation.id() ); current_operation.getFirstChild( "input" ).deepCopy( setName( name )); current_operation.getFirstChild( "input").getFirstChild( "name" ).setValue( oneWayOperation.requestType().id() ); if ( !isNativeType( oneWayOperation.requestType().id() )) { addType( types, oneWayOperation.requestType()); } } else { RequestResponseOperationDeclaration requestResponseOperation = ( RequestResponseOperationDeclaration ) operationEntry.getValue(); current_operation.getFirstChild("operation_name").setValue( requestResponseOperation.id() ); current_operation.getFirstChild( "input" ).deepCopy( setName( name )); current_operation.getFirstChild("input").getFirstChild( "name" ).setValue( requestResponseOperation.requestType().id() ); current_operation.getFirstChild("output").deepCopy( setName( name )); current_operation.getFirstChild("output").getFirstChild( "name" ).setValue( requestResponseOperation.responseType().id() ); if ( !isNativeType( requestResponseOperation.requestType().id())) { addType( types, requestResponseOperation.requestType() ); } if ( !isNativeType( requestResponseOperation.responseType().id())) { addType( types, requestResponseOperation.responseType() ); } } operations.add( current_operation ); } return response; } private List<InterfaceDefinition> addInterfaceToList ( List<InterfaceDefinition> list, InterfaceDefinition intf ) { if ( !list.contains( intf ) ) { list.add( intf ); } return list; } private Value setName( String name ) { Value v = Value.create(); v.getFirstChild( "name").setValue( name ); return v; } private Value setName( String name, String domain ) { Value v = setName( name ); v.getFirstChild( "domain" ).setValue( domain ); return v; } private Value setName( String name, String domain, String registry ) { Value v = setName( name, domain ); v.getFirstChild( "registry" ).setValue( registry ); return v; } private Value setName( Value name ) { Value v; if ( name.getFirstChild( "domain" ).isDefined() && name.getFirstChild( "registry" ).isDefined() ) { v = setName( name.getFirstChild( "name").strValue(), name.getFirstChild( "domain" ).strValue(), name.getFirstChild( "registry").strValue() ); } else if ( name.getFirstChild( "domain" ).isDefined() && !name.getFirstChild( "registry" ).isDefined() ) { v = setName( name.getFirstChild( "name").strValue(), name.getFirstChild( "domain" ).strValue() ); } else { v = setName( name.getFirstChild( "name").strValue() ); } return v; } private Value getPort( PortInfo portInfo, Value name ) { Value response = Value.create(); response.getFirstChild("name").deepCopy( setName( name ) ); // setting the name of the port response.getFirstChild("name").getFirstChild("name").setValue( portInfo.id() ); if ( portInfo instanceof InputPortInfo ) { InputPortInfo port = ( InputPortInfo ) portInfo; response.getFirstChild("location").setValue( port.location().toString() ); if ( port.protocolId() != null ) { response.getFirstChild("protocol").setValue( port.protocolId() ); } else { response.getFirstChild("protocol").setValue( "" ); } } else if ( portInfo instanceof OutputPortInfo ) { OutputPortInfo port = ( OutputPortInfo ) portInfo; response.getFirstChild("location").setValue( port.location().toString() ); if ( port.protocolId() != null ) { response.getFirstChild("protocol").setValue( port.protocolId() ); } else { response.getFirstChild("protocol").setValue( "" ); } } ArrayList<TypeDefinition> types = new ArrayList<TypeDefinition>(); // scan all the interfaces first interface for( int intf_index = 0; intf_index < portInfo.getInterfaceList().size(); intf_index++ ) { InterfaceDefinition interfaceDefinition = portInfo.getInterfaceList().get( intf_index ); Value input_interface = response.getFirstChild("interfaces"); input_interface.getFirstChild("name").deepCopy( setName( name )); input_interface.getFirstChild( "name").getFirstChild( "name" ).setValue( interfaceDefinition.name() ); ValueVector operations = input_interface.getChildren("operations"); ValueVector interface_types = input_interface.getChildren("types"); // scans operations and types Map< String , OperationDeclaration > operationMap = interfaceDefinition.operationsMap(); for ( Entry< String , OperationDeclaration > operationEntry:operationMap.entrySet() ) { Value current_operation = Value.create();; if ( operationEntry.getValue() instanceof OneWayOperationDeclaration ) { OneWayOperationDeclaration oneWayOperation = ( OneWayOperationDeclaration)operationEntry.getValue(); current_operation.getFirstChild( "operation_name").setValue( oneWayOperation.id() ); current_operation.getFirstChild("input").deepCopy( setName( name )); current_operation.getFirstChild( "input").getFirstChild( "name").setValue( oneWayOperation.requestType().id() ); if ( !isNativeType( oneWayOperation.requestType().id() )) { insertType( types, interface_types, name, oneWayOperation.requestType()); } } else { RequestResponseOperationDeclaration requestResponseOperation = ( RequestResponseOperationDeclaration ) operationEntry.getValue(); current_operation.getFirstChild("operation_name").setValue( requestResponseOperation.id() ); current_operation.getFirstChild("input").deepCopy( setName( name )); current_operation.getFirstChild( "input").getFirstChild( "name").setValue( requestResponseOperation.requestType().id() ); current_operation.getFirstChild("output").deepCopy( setName( name )); current_operation.getFirstChild("output").getFirstChild("name").setValue( requestResponseOperation.responseType().id() ); if ( !isNativeType( requestResponseOperation.requestType().id())) { insertType( types, interface_types, name, requestResponseOperation.requestType() ); } if ( !isNativeType( requestResponseOperation.responseType().id())) { insertType( types, interface_types, name, requestResponseOperation.responseType() ); } } operations.add( current_operation ); } } return response; } private Value getPort( PortInfo portInfo, Value name, List<InterfaceDefinition> interfaces ) { Value response = Value.create(); // setting domain and registry from request response.getFirstChild("name").deepCopy( setName( name ) ); // setting the name of the port response.getFirstChild("name").getFirstChild("name").setValue( portInfo.id() ); if ( portInfo instanceof InputPortInfo ) { InputPortInfo port = ( InputPortInfo ) portInfo; if ( port.location() != null ) { response.getFirstChild("location").setValue( port.location().toString() ); } else { response.getFirstChild("location").setValue( "local" ); } if ( port.protocolId() != null ) { response.getFirstChild("protocol").setValue( port.protocolId() ); } else { response.getFirstChild("protocol").setValue( "" ); } } else if ( portInfo instanceof OutputPortInfo ) { OutputPortInfo port = ( OutputPortInfo ) portInfo; if ( port.location() != null ) { response.getFirstChild("location").setValue( port.location().toString() ); } else { response.getFirstChild("location").setValue( "local" ); } if ( port.protocolId() != null ) { response.getFirstChild("protocol").setValue( port.protocolId() ); } else { response.getFirstChild("protocol").setValue( "" ); } } // scans interfaces List<InterfaceDefinition> interfaceList = portInfo.getInterfaceList(); for ( int intf = 0; intf < interfaceList.size(); intf++ ) { InterfaceDefinition interfaceDefinition = portInfo.getInterfaceList().get( intf ); // setting the name of the interface within the port response response.getChildren( "interfaces" ).get( intf ).getFirstChild( "name" ).deepCopy( setName( name )); response.getChildren( "interfaces" ).get( intf ).getFirstChild( "name" ).getFirstChild( "name").setValue( interfaceDefinition.name() ); interfaces = addInterfaceToList( interfaces, interfaceDefinition ); } return response; } @RequestResponse public Value parseRoles( Value request ) { Value response = Value.create(); try { response.getFirstChild("name").deepCopy( setName( request.getFirstChild( "rolename") )); String[] args = new String[] { request.getFirstChild("filename").strValue(), "-i", "/opt/jolie/include"}; CommandLineParser cmdParser = new CommandLineParser( args, MetaJolie.class.getClassLoader() ); args = cmdParser.arguments(); Program program = ParsingUtils.parseProgram( cmdParser.programStream(), URI.create( "file:" + cmdParser.programFilepath() ), cmdParser.includePaths(), MetaJolie.class.getClassLoader(), cmdParser.definedConstants() ); ProgramInspector inspector=ParsingUtils.createInspector( program ); URI originalFile = program.context().source(); // scanning first inputport InputPortInfo[] inputPortList = inspector.getInputPorts( originalFile ); Value input = response.getFirstChild("input"); if ( inputPortList.length > 0 ) { InputPortInfo inputPort = inputPortList[0]; input.deepCopy( getPort ( inputPort, request.getFirstChild( "name") )); } // scanning first outputPort if it exists OutputPortInfo[] outputPortList = inspector.getOutputPorts(); if ( outputPortList.length > 0 ) { Value output = response.getFirstChild("output"); output.deepCopy( getPort( outputPortList[0], request.getFirstChild( "name") )); } } catch ( CommandLineException e ) { // TO DO e.printStackTrace(); } catch( IOException e ) { // TO DO e.printStackTrace(); } catch( ParserException e ) { // TO DO e.printStackTrace(); } return response; } @RequestResponse public Value getMetaData( Value request ) { String domain = ""; List<TypeDefinition> types = new ArrayList<TypeDefinition>(); List<InterfaceDefinition> interfaces = new ArrayList<InterfaceDefinition>(); Value response = Value.create(); try { String[] args = new String[] { request.getFirstChild("filename").strValue(), "-i", "/opt/jolie/include"}; if ( request.getFirstChild("name").getFirstChild( "domain" ).isDefined() ) { domain = request.getFirstChild("name").getFirstChild( "domain" ).strValue(); } CommandLineParser cmdParser = new CommandLineParser( args, MetaJolie.class.getClassLoader() ); args = cmdParser.arguments(); Program program = ParsingUtils.parseProgram( cmdParser.programStream(), URI.create( "file:" + cmdParser.programFilepath() ), cmdParser.includePaths(), MetaJolie.class.getClassLoader(), cmdParser.definedConstants() ); ProgramInspector inspector=ParsingUtils.createInspector( program ); URI originalFile = program.context().source(); response.getFirstChild( "service" ).getFirstChild( "name").deepCopy( setName( request.getFirstChild( "name" ) )); InputPortInfo[] inputPortList = inspector.getInputPorts( originalFile ); ValueVector input = response.getChildren("input"); if ( inputPortList.length > 0 ) { for( int ip = 0; ip < inputPortList.length; ip++ ) { InputPortInfo inputPort = inputPortList[ ip ]; input.get( ip ).deepCopy( getPort ( inputPort, request.getFirstChild( "name"), interfaces )); response.getFirstChild( "service" ).getChildren( "input" ).get( ip ).getFirstChild( "name" ).setValue( inputPort.id() ); response.getFirstChild( "service" ).getChildren( "input" ).get( ip ).getFirstChild( "domain" ).setValue( domain ); } } OutputPortInfo[] outputPortList = inspector.getOutputPorts(); if ( outputPortList.length > 0 ) { ValueVector output = response.getChildren("output"); for ( int op = 0; op < outputPortList.length; op++ ) { OutputPortInfo outputPort = outputPortList[ op ]; output.get( op ).deepCopy( getPort( outputPort, request.getFirstChild( "name"), interfaces )); response.getFirstChild( "service" ).getChildren( "output" ).get( op ).getFirstChild( "name" ).setValue( outputPort.id() ); response.getFirstChild( "service" ).getChildren( "output" ).get( op ).getFirstChild( "domain" ).setValue( domain ); } } // adding interfaces for( int intf = 0; intf < interfaces.size(); intf++ ) { InterfaceDefinition interfaceDefinition = interfaces.get( intf ); response.getChildren("interfaces").get( intf ).deepCopy( getInterface( interfaceDefinition, request.getFirstChild( "name"), types )); } // adding types for ( int tp = 0; tp < types.size(); tp++ ) { TypeDefinition typeDefinition = types.get( tp ); response.getChildren( "types" ).get( tp ).deepCopy( getType( typeDefinition, request.getFirstChild( "name" ) )); } } catch ( CommandLineException e ) { // TO DO e.printStackTrace(); } catch( IOException e ) { // TO DO e.printStackTrace(); } catch( ParserException e ) { // TO DO e.printStackTrace(); } return response; } @RequestResponse public Value getInputPortMetaData( Value request ) { String domain = ""; List<TypeDefinition> types = new ArrayList<TypeDefinition>(); List<InterfaceDefinition> interfaces = new ArrayList<InterfaceDefinition>(); Value response = Value.create(); try { String[] args = new String[] { request.getFirstChild("filename").strValue(), "-i", "/opt/jolie/include"}; if ( request.getFirstChild( "domain" ).isDefined() ) { domain = request.getFirstChild( "domain" ).strValue(); } CommandLineParser cmdParser = new CommandLineParser( args, MetaJolie.class.getClassLoader() ); args = cmdParser.arguments(); Program program = ParsingUtils.parseProgram( cmdParser.programStream(), URI.create( "file:" + cmdParser.programFilepath() ), cmdParser.includePaths(), MetaJolie.class.getClassLoader(), cmdParser.definedConstants() ); ProgramInspector inspector=ParsingUtils.createInspector( program ); URI originalFile = program.context().source(); InputPortInfo[] inputPortList = inspector.getInputPorts( originalFile ); ValueVector input = response.getChildren("input"); if ( inputPortList.length > 0 ) { for( int ip = 0; ip < inputPortList.length; ip++ ) { InputPortInfo inputPort = inputPortList[ ip ]; input.get( ip ).deepCopy( getPort ( inputPort, request.getFirstChild( "name") )); } } } catch ( CommandLineException e ) { // TO DO e.printStackTrace(); } catch( IOException e ) { // TO DO e.printStackTrace(); } catch( ParserException e ) { // TO DO e.printStackTrace(); } return response; } }