/*******************************************************************************
* ALMA - Atacama Large Millimeter Array
* Copyright (c) ESO - European Southern Observatory, 2011
* (in the framework of the ALMA collaboration).
* All rights reserved.
*
* 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.1 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
*******************************************************************************/
package alma.tools.idlgen;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.jacorb.idl.AcsInterfacePrinter;
import org.jacorb.idl.AcsStructPrinter;
import org.jacorb.idl.AliasTypeSpec;
import org.jacorb.idl.ConstrTypeSpec;
import org.jacorb.idl.Interface;
import org.jacorb.idl.StructType;
import org.jacorb.idl.TypeDeclaration;
import org.jacorb.idl.TypeSpec;
import org.jacorb.idl.VectorType;
/**
* See old alma.tools.idlgen.NamingConventions
*
* @author hsommer
*/
public class AcsXmlNamingExpert
{
private Map<String, String> struct2JavaMap = new HashMap<String, String>();
public static final String suffix = "J";
////////////////////////////////////////////////////////////////////////////////////
///////////////////////// Java binding classes /////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
/**
* Sets the mappings from <code>XmlEntityStruct</code> typedefs to
* Java binding classes.
* For example, <code>ObsProposal=alma.xmljbind.test.obsproposal.ObsProposal</code>
* would substitute the Java class on the right side for the IDL type ObsProposal,
* which is defined as <code>typedef xmlentity::XmlEntityStruct ObsProposal;</code>
* in the IDL file.
* @param mappings concatenated mappings, separated by ';'
*/
public void setIdlStruct2JavaBindingClassMappings(String mappings)
{
if (mappings == null) {
return;
}
for (String mapping : mappings.split(";")) {
String trimmedMapping = mapping.trim();
int sepPos = trimmedMapping.indexOf('=');
if (sepPos > 0) {
String structName = trimmedMapping.substring(0, sepPos).trim();
String bindingClassName = trimmedMapping.substring(sepPos + 1).trim();
struct2JavaMap.put(structName, bindingClassName);
}
}
}
public String getBindingClassName(String idlTypedefName) {
return struct2JavaMap.get(idlTypedefName);
}
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////// Structs /////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
public String getClassNameForStruct(StructType struct) {
return ( struct.name() + suffix );
}
public String getHolderClassNameForStruct(StructType struct) {
String className = getClassNameForStruct(struct);
className += "Holder";
return className;
}
public String getJavaPackageForStruct(StructType struct) {
// java_name or full_name takes care of adding "Package" for typedefs defined inside IDL interfaces
// These methods are package private for jacorb so that we call them through our own class in that package.
String fullName = AcsStructPrinter.java_name(struct);// full_name();
int index = fullName.lastIndexOf('.');
String jpackage = null;
if (index > 0) {
jpackage = fullName.substring(0, fullName.lastIndexOf('.'));
}
else {
jpackage = fullName;
}
return jpackage;
}
/**
* Gets the fully qualified name of the java class that represents the struct
* in the world of "J" classes.
*/
public String getJavaTypeForXmlStruct(StructType struct) {
String ret = getJavaPackageForStruct(struct) + '.' + getClassNameForStruct(struct);
return ret;
}
////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////// Interfaces ///////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
/**
* Currently assumes that the trailing "J" has already been appended
* to the name of the provided <code>interfce</code>.
* @TODO Change the logic to not rename interfaces in the parse tree and add suffix here to the interface name.
*/
public String getClassNameForInterface(Interface interfce) {
// return ( interfce.name() + suffix );
return ( interfce.name());
}
public String getJavaPackageForInterface(Interface interfce) {
String fullName = AcsInterfacePrinter.java_name(interfce);
int index = fullName.lastIndexOf('.');
String jpackage = null;
if (index > 0) {
jpackage = fullName.substring(0, fullName.lastIndexOf('.'));
}
else {
jpackage = fullName;
}
return jpackage;
}
public String getJavaTypeForXmlInterface(Interface interfce) {
String ret = getJavaPackageForInterface(interfce) + '.' + getClassNameForInterface(interfce);
return ret;
}
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////// Typedefs ////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
/**
* TODO: Try to reuse this code for the interface and struct code generation.
* Also remove code duplication with JacorbVisitor#isOrHasXmlEntityStruct
*/
public String getClassNameForXmlTypedef(AliasTypeSpec alias) {
String className = alias.name();
XmlTypedefInfo info = new XmlTypedefInfo();
checkXmlTypedef(alias, info);
if (!info.isXmlEntityStruct || info.isSequence) {
className += suffix;
}
return className;
}
/**
* TODO: Try to reuse this code for the interface and struct code generation.
* Also remove code duplication with JacorbVisitor#isOrHasXmlEntityStruct
*/
public String getHolderClassNameForXmlTypedef(AliasTypeSpec alias) {
String className = getClassNameForXmlTypedef(alias);
className += "Holder";
return className;
}
/**
* Gets the fully qualified name of the java class that represents the typedef
* in the world of "J" classes, that is, either a binding class or a class
* that represents an xml affected struct or interface.
*/
public String getJavaTypeForXmlTypedef(AliasTypeSpec alias) {
XmlTypedefInfo info = new XmlTypedefInfo();
checkXmlTypedef(alias, info);
if (info.isSequence) {
info.javaType += "[]";
}
return info.javaType;
}
/**
* Auxiliary class to return multiple fields from {@link #checkXmlTypedef}.
*/
private static class XmlTypedefInfo {
boolean isXmlEntityStruct = false;
boolean isSequence = false;
/**
* Fully qualified name of the "J" class.
*/
String javaType;
}
/**
* TODO: Try to reuse this type printing code for the interface and struct code generation.
* Also remove code duplication with JacorbVisitor#isOrHasXmlEntityStruct
*/
private void checkXmlTypedef(AliasTypeSpec alias, XmlTypedefInfo info) {
TypeSpec orgType = alias.originalType();
if (orgType instanceof VectorType) {
info.isSequence = true;
// Continue by checking the type that we have a sequence of
VectorType vector = (VectorType) orgType;
orgType = vector.elementTypeSpec();
}
if (orgType instanceof AliasTypeSpec) {
checkXmlTypedef((AliasTypeSpec)orgType, info);
}
else if (orgType instanceof ConstrTypeSpec) {
TypeDeclaration decl = ((ConstrTypeSpec) orgType.typeSpec()).c_type_spec.declaration();
if (decl instanceof StructType && ((StructType) decl).name().equals(JacorbVisitor.XML_ENTITY_STRUCT_NAME)) {
// alias is directly a typedef'd XmlEntityStruct. We use the xml binding class name.
info.isXmlEntityStruct = true;
info.javaType = getBindingClassName(alias.name());
}
else {
// It is some user-defined struct or interface that contains xml types.
TypeDeclaration decl2 = ((ConstrTypeSpec) orgType).c_type_spec;
if (decl2 instanceof StructType) {
StructType struct = (StructType) decl2;
info.javaType = getJavaTypeForXmlStruct(struct);
}
else if (decl2 instanceof Interface) {
Interface interfce = (Interface) decl2;
info.javaType = decl2.typeName(); // TODO: convert to "J", prepend package
}
}
}
}
public String getAcsTypeName(TypeSpec tspec, Set<AliasTypeSpec> xmlTypedefs, Set<StructType> xmlAwareStructs, Set<Interface> xmlAwareIFs) {
String acsTypeName = null;
if (tspec instanceof AliasTypeSpec) {
if (xmlTypedefs.contains(tspec)) {
acsTypeName = getJavaTypeForXmlTypedef((AliasTypeSpec)tspec);
}
}
else if (tspec instanceof ConstrTypeSpec) {
TypeDeclaration decl = ((ConstrTypeSpec)tspec).c_type_spec;
if (decl instanceof StructType && xmlAwareStructs.contains(decl)) {
acsTypeName = getJavaTypeForXmlStruct((StructType)((ConstrTypeSpec)tspec).c_type_spec.declaration());
}
else if (decl instanceof Interface) {
Interface interfce = JacorbVisitor.resolveForwardDecl((Interface)decl);
if (xmlAwareIFs.contains(interfce)) {
acsTypeName = getJavaTypeForXmlInterface(interfce);
}
}
}
// default member type output:
if (acsTypeName == null) {
// Note that Member#member_print is fancier, but its fanciness apparently does not apply
// to our case because StructType#printStructClass later gets the data for the constructors
// in the same simple way that we do here.
acsTypeName = tspec.toString();
}
return acsTypeName;
}
}