/*=============================================================================*
* Copyright 2006 The Apache Software Foundation
*
* Licensed 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.muse.tools.generator.synthesizer;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.xml.namespace.QName;
import org.apache.muse.core.AbstractCapability;
import org.apache.muse.tools.generator.util.Capability;
import org.apache.muse.tools.generator.util.ConfigurationData;
import org.apache.muse.tools.generator.util.ConfigurationDataDescriptor;
import org.apache.muse.tools.inspector.JavaMethod;
import org.apache.muse.tools.inspector.JavaProperty;
import org.apache.muse.util.ReflectUtils;
import org.apache.muse.ws.resource.impl.AbstractWsResourceCapability;
/**
* A <code>Synthesizer</code> implementation that creates
* the server-side stubs for a set of capabilities. This involves creating
* accessors and constants for any properties and creating the operation
* templates that are to be filled-in by implementors. Unlike
* <code>ProxyGenerator</code> the code that comes out of this
* phase will throw Exceptions when any method is invoked because by
* default the methods have no implementation and simply throw
*
* <code>new RuntimeException("Unimplemented Method");");</code>
*
* @author Andrew Eberbach (aeberbac)
*
* @see org.apache.muse.tools.generator.synthesizer.Synthesizer
*/
public class ServerSynthesizer implements Synthesizer {
private static final String INDENT = " ";
private static final String REQUEST_SUFFIX = "Request";
private static final String IMPL_SUFFIX = "Impl";
static final String INTERFACE_PREFIX = "I";
protected Map[] _filesMaps = null;
static ConfigurationDataDescriptor[] REQUIRED_PARAMETERS =
new ConfigurationDataDescriptor[] {
ConfigurationData.CAPABILITIES_MAP_LIST_CONFIGURATION,
};
public ConfigurationData synthesize(ConfigurationData configuration) throws Exception {
ConfigurationData.checkConfiguration(this, configuration);
Map[] capabilityMaps = (Map[])configuration.getParameter(ConfigurationData.CAPABILITIES_MAP_LIST);
_filesMaps = new HashMap[capabilityMaps.length];
for(int i = 0; i < capabilityMaps.length; i++) {
Map capabilities = capabilityMaps[i];
_filesMaps[i] = new HashMap();
for (Iterator j = capabilities.values().iterator(); j.hasNext();) {
Capability capability = (Capability)j.next();
if(!capability.isBuiltIn()) {
generateCapability(capability, _filesMaps[i]);
}
}
}
ConfigurationData resultData = (ConfigurationData) configuration.clone();
resultData.addParameter(ConfigurationData.FILES_MAP_LIST, _filesMaps);
return resultData;
}
protected void generateCapability(Capability capability, Map files) {
ClassInfo classInfo = new ClassInfo(capability);
makeInterface(classInfo, files);
makeAbstractClass(classInfo, files);
}
protected void makeInterface(ClassInfo classInfo, Map files) {
StringBuffer code = new StringBuffer();
generatePackageHeader(classInfo, code);
generateImports(classInfo, false, code);
generateInterfaceDeclaration(classInfo, code);
generateOpenBlock(code);
newLine(code);
generateNSDeclarations(classInfo, code);
generatePropertyOperations(classInfo, code, false);
generateOperations(classInfo, code, false);
generateCloseBlock(code);
String className = makeFileName(classInfo, true);
files.put(className, code.toString());
}
private void makeAbstractClass(ClassInfo classInfo, Map files) {
StringBuffer code = new StringBuffer();
generatePackageHeader(classInfo, code);
generateImports(classInfo, true, code);
generateClassDeclaration(classInfo, code);
generateOpenBlock(code);
newLine(code);
generatePropertiesDeclarations(classInfo, code);
generatePropertyOperations(classInfo, code, true);
generateOperations(classInfo, code, true);
generateCloseBlock(code);
String className = makeFileName(classInfo, false);
files.put(className, code.toString());
}
private void generateInterfaceDeclaration(ClassInfo classInfo, StringBuffer code) {
code.append("public interface "
+ getInterfaceName(classInfo.getClassShortName()));
newLine(code);
}
private String getInterfaceName(String classShortName) {
int indexOfImpl = classShortName.indexOf(IMPL_SUFFIX);
if(indexOfImpl > 0) {
classShortName = classShortName.substring(0, indexOfImpl);
}
return INTERFACE_PREFIX + classShortName;
}
protected void generateClassDeclaration(ClassInfo classInfo, StringBuffer code) {
Capability capability = classInfo.getCapability();
code.append("public class "
+ ReflectUtils.getShortName(capability.getImplementingClass())
+ " extends "
+ convertType(getBaseClass(capability),classInfo));
code.append(" implements " + getInterfaceName(classInfo.getClassShortName()));
newLine(code);
}
private void generatePropertiesDeclarations(ClassInfo classInfo, StringBuffer code) {
Capability capability = classInfo.getCapability();
if(capability.getProperties().size() == 0) {
return;
}
indent(code);
code.append("private static final "
+ convertType(QName.class, classInfo)
+ "[] _PROPERTIES = new "
+ convertType(QName.class, classInfo)
+ "[]");
newLine(code);
indent(code);
generateOpenBlock(code);
newLine(code);
for(Iterator i=capability.getProperties().iterator(); i.hasNext();) {
JavaProperty property = (JavaProperty)i.next();
indent(2,code);
code.append("new "
+ convertType(QName.class, classInfo)
+ "(NAMESPACE_URI, \""
+ getPropertyName(property, false)
+ "\", PREFIX)");
if(i.hasNext()) {
code.append(",");
}
newLine(code);
}
indent(code);
generateCloseBlock(code);
statement(";",code);
newLine(2,code);
indent(code);
code.append("public "
+ convertType(QName.class, classInfo)
+ "[] getPropertyNames()");
newLine(code);
indent(code);
generateOpenBlock(code);
newLine(code);
indent(2,code);
code.append("return _PROPERTIES;");
newLine(code);
indent(code);
generateCloseBlock(code);
newLine(2,code);
for(Iterator i=capability.getProperties().iterator(); i.hasNext();) {
JavaProperty property = (JavaProperty)i.next();
indent(code);
code.append("private "
+ convertType(property.getJavaType(), classInfo)
+ " _"
+ getPropertyName(property, false)
+ ";");
newLine(2, code);
}
}
private String getPropertyName(JavaProperty property, boolean forSetter) {
String name = property.getName().getLocalPart();
if(!forSetter) {
return name;
}
name = name.substring(0,1).toUpperCase() + name.substring(1);
return name;
}
protected void generateOperations(ClassInfo classInfo, StringBuffer code, boolean generateBody) {
Capability capability = classInfo.getCapability();
for(Iterator i=capability.getOperations().iterator(); i.hasNext();) {
JavaMethod method = (JavaMethod)i.next();
indent(code);
code.append("public "
+ convertType(method.getReturnType(), classInfo)
+ " " + getMethodName(method));
Class[] params = method.getParameterTypes();
code.append("(");
if (params.length > 0) {
int j;
for (j = 0; j < params.length - 1; j++) {
code.append(convertType(params[j], classInfo)
+ " "
+ "param"
+ j
+ ", ");
}
code.append(convertType(params[j], classInfo)
+ " "
+ "param" + j);
}
code.append(") throws Exception");
if(generateBody) {
indent(code);
generateOpenBlock(code);
newLine(code);
indent(2,code);
code.append("//TODO implement " + getMethodName(method));
newLine(code);
indent(2,code);
code.append("throw new RuntimeException(\"Unimplemented Method: " + getMethodName(method) + "\");");
newLine(code);
indent(code);
generateCloseBlock(code);
} else {
code.append(";");
}
newLine(2,code);
}
}
private void generatePropertyOperations(ClassInfo classInfo, StringBuffer code, boolean generateBody) {
Capability capability = classInfo.getCapability();
if(capability.getProperties().size() == 0) {
return;
}
for(Iterator i=capability.getProperties().iterator(); i.hasNext();) {
JavaProperty property = (JavaProperty)i.next();
indent(code);
code.append("public "
+ convertType(property.getJavaType(), classInfo)
+ " get"
+ getPropertyName(property, true)
+ "()");
if(generateBody) {
newLine(code);
indent(code);
generateOpenBlock(code);
newLine(code);
indent(2,code);
statement("return _"
+ getPropertyName(property, false)
+ ";",code);
newLine(code);
indent(code);
generateCloseBlock(code);
} else {
code.append(";");
}
newLine(2,code);
indent(code);
code.append("public void");
code.append(" set"
+ getPropertyName(property, true)
+ "("
+ convertType(property.getJavaType(), classInfo)
+ " param0)");
if(generateBody) {
newLine(code);
indent(code);
generateOpenBlock(code);
newLine(code);
indent(2,code);
statement("_"
+ getPropertyName(property, false)
+ " = param0;",code);
newLine(code);
indent(code);
generateCloseBlock(code);
} else {
code.append(";");
}
newLine(2,code);
}
}
private void generateNSDeclarations(ClassInfo classInfo, StringBuffer code) {
Capability capability = classInfo.getCapability();
indent(code);
statement("String PREFIX = \"tns\";", code);
newLine(2,code);
indent(code);
statement("String NAMESPACE_URI = \""+ capability.getURI() +"\";", code);
newLine(2,code);
}
protected void generateImports(ClassInfo classInfo, boolean isImpl, StringBuffer code) {
Set imports = classInfo.getImports();
Class baseClass = getBaseClass(classInfo.getCapability());
if(isImpl && !imports.contains(baseClass)) {
generateImport(baseClass, code);
}
if(classInfo.getCapability().getProperties().size() > 0) {
if(!imports.contains(QName.class)) {
generateImport(QName.class, code);
}
}
for (Iterator i = imports.iterator(); i.hasNext(); ) {
generateImport((Class)i.next(),code);
}
newLine(code);
}
private void generateImport(Class theClass, StringBuffer code) {
String className = needsImport(theClass);
if (className != null) {
code.append("import " + className + ";");
code.append("\n");
}
}
protected void generatePackageHeader(ClassInfo classInfo, StringBuffer code) {
statement("package " + classInfo.getPackageName() + ";",code);
newLine(2, code);
}
protected String getMethodName(JavaMethod method) {
String name = method.getName().getLocalPart();
name = name.substring(0,1).toLowerCase() + name.substring(1);
if(name.endsWith(REQUEST_SUFFIX)) {
name = name.substring(0, name.indexOf(REQUEST_SUFFIX));
}
return name;
}
protected String needsImport(Class className) {
if(className.isPrimitive()) {
return null;
}
if(className.isArray()) {
className = ReflectUtils.getClassFromArrayClass(className);
}
if(className.getName().startsWith("java.lang.")) {
return null;
}
return className.getName();
}
protected String convertType(Class returnType, ClassInfo classInfo) {
boolean isArray = returnType.isArray();
returnType = isArray?ReflectUtils.getClassFromArrayClass(returnType):returnType;
//Use fully-qualified name if conflict exists
if(classInfo.hasConflict(returnType)) {
return returnType.getName();
}
return ReflectUtils.getShortName(returnType);
}
protected Class getBaseClass(Capability capability) {
if(capability.getProperties().size() > 0) {
return AbstractWsResourceCapability.class;
}
return AbstractCapability.class;
}
protected String makeFileName(ClassInfo classInfo, boolean isInterface) {
String name = name = classInfo.getPackageName() + ".";
if(isInterface) {
name += getInterfaceName(classInfo.getClassShortName());
} else {
name += classInfo.getClassShortName();
}
return name.replaceAll("\\.", "\\" + File.separator) + ".java";
}
protected void statement(String statement, StringBuffer code) {
code.append(statement);
}
protected void newLine(StringBuffer code) {
newLine(1,code);
}
protected void newLine(int n, StringBuffer code) {
for(int i=0; i < n; i++) {
code.append("\n");
}
}
protected void generateCloseBlock(StringBuffer code) {
code.append("}");
}
protected void generateOpenBlock(StringBuffer code) {
code.append("{");
}
protected void indent(StringBuffer code) {
indent(1,code);
}
protected void indent(int indent, StringBuffer code) {
for(int i=0; i < indent; i++) {
code.append(INDENT);
}
}
public ConfigurationDataDescriptor[] getConfigurationDataDescriptions() {
return REQUIRED_PARAMETERS;
}
}