org.jace.peer.PeerGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jace-core-java Show documentation
Show all versions of jace-core-java Show documentation
Jace core module, Java source-code
package org.jace.peer;
import com.google.common.collect.Lists;
import java.io.*;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.jace.metaclass.*;
import org.jace.parser.ClassFile;
import org.jace.parser.method.ClassMethod;
import org.jace.parser.method.MethodAccessFlag;
import org.jace.proxy.ClassPath;
import org.jace.proxy.ProxyGenerator;
import org.jace.proxy.ProxyGenerator.AccessibilityType;
import org.jace.proxy.ProxyGenerator.InvokeStyle;
import org.jace.util.DelimitedCollection;
import org.jace.util.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Generates a Java implementation, and a C++ peer for the specified class.
*
* @author Toby Reyelts
* @author Gili Tzabari
*/
public class PeerGenerator
{
private static final String newLine = System.getProperty("line.separator");
private final Logger log = LoggerFactory.getLogger(PeerGenerator.class);
private final ClassFile classFile;
private final long lastModified;
private final ClassMetaClass metaClass;
private final ClassMetaClass proxyMetaClass;
private final File includeDir;
private final File sourceDir;
private final boolean userDefinedMembers;
/**
* Constructs a new PeerGenerator for the given class.
*
* @param classFile the Java class that needs a C++ peer
* @param lastModified the date the class file was last modified
* @param includeDir the directory containing the output header files
* @param sourceDir the directory containing the output source files
* @param userDefinedMembers true if <peer_class_name>_user.h should be generated
*/
public PeerGenerator(ClassFile classFile, long lastModified, File includeDir, File sourceDir,
boolean userDefinedMembers)
{
this.classFile = classFile;
this.lastModified = lastModified;
proxyMetaClass =
(ClassMetaClass) MetaClassFactory.getMetaClass(classFile.getClassName()).proxy();
metaClass = proxyMetaClass.unProxy();
this.includeDir = includeDir;
this.sourceDir = sourceDir;
this.userDefinedMembers = userDefinedMembers;
}
/**
* Generates the C++ peer.
*
* @throws IOException if an error occurs while writing the files
*/
public void generate() throws IOException
{
MetaClass peerMetaClass = metaClass.toPeer();
String directory =
peerMetaClass.getPackage().toName("/", false).replace('/', File.separatorChar);
File includeDirectory = new File(includeDir, directory);
File sourceDirectory = new File(sourceDir, directory);
File cppHeader = new File(includeDirectory, peerMetaClass.getSimpleName() + ".h");
File actualDirectory = cppHeader.getParentFile();
if (!actualDirectory.exists() && !actualDirectory.mkdirs())
throw new IOException("Failed to create " + actualDirectory);
if (lastModified > cppHeader.lastModified())
{
BufferedWriter out = new BufferedWriter(new FileWriter(cppHeader));
try
{
generateCppPeerHeader(out);
}
finally
{
out.close();
}
}
File cppMappings = new File(sourceDirectory, peerMetaClass.getSimpleName() + "Mappings.cpp");
actualDirectory = cppMappings.getParentFile();
if (!actualDirectory.exists() && !actualDirectory.mkdirs())
throw new IOException("Failed to create " + actualDirectory);
if (lastModified > cppMappings.lastModified())
{
BufferedWriter out = new BufferedWriter(new FileWriter(cppMappings));
try
{
generateCppPeerMappings(out);
}
finally
{
out.close();
}
}
File cppSource = new File(sourceDirectory, peerMetaClass.getSimpleName() + "_peer.cpp");
actualDirectory = cppSource.getParentFile();
if (!actualDirectory.exists() && !actualDirectory.mkdirs())
throw new IOException("Failed to create " + actualDirectory);
if (lastModified > cppSource.lastModified())
{
BufferedWriter out = new BufferedWriter(new FileWriter(cppSource));
try
{
generateCppPeerSource(out);
}
finally
{
out.close();
}
}
}
/**
* Generates a C++ peer header.
*
* @param output the output writer
* @throws IOException if an error occurs while writing
*/
private void generateCppPeerHeader(Writer output) throws IOException
{
MetaClass peerMetaClass = metaClass.toPeer();
output.write(peerMetaClass.beginGuard() + newLine);
output.write(newLine);
// Generate the #includes
ProxyGenerator proxyGen = new ProxyGenerator.Builder(new ClassPath(
System.getProperty("java.class.path")), classFile,
new ProxyGenerator.AcceptAll()).accessibility(AccessibilityType.PRIVATE).build();
proxyGen.includeStandardHeaders(output, true);
output.write(newLine);
Util.generateComment(output, "The Peer class from which this class derives.");
output.write("#include \"jace/Peer.h\"" + newLine);
output.write(newLine);
proxyGen.includeDependentHeaders(output);
proxyGen.makeForwardDeclarations(output);
output.write(newLine);
// The ProxyGenerator explicitly disallows a class from including itself,
// but the problem is that we're creating a peer, and it may actually
// depend upon its proxy. (For example, a Singleton's getInstance method).
//
// We could walk through the set of methods/fields to figure this out, but for
// now we'll just always include it.
output.write(proxyMetaClass.include() + newLine);
output.write(newLine);
beginNamespace(output);
output.write(newLine);
// Generate the class declaration
String name = metaClass.getSimpleName();
Util.generateComment(output, name + newLine + newLine
+ "This header provides the declaration for the Jace Peer, "
+ name + "." + newLine
+ "To complete this Peer, you must create a new source file containing the"
+ newLine
+ "definitions for all native methods declared for this Peer."
+ newLine + newLine
+ "You may also override initialize() and destroy(), if your Peer requires"
+ newLine
+ "custom initialization or destruction.");
output.write("class " + name + " : public ::jace::Peer, public ");
// If we are derived directly from java.lang.Object, we need to derive from it virtually
assert (classFile.getSuperClassName() != null): "java.lang.Object may not be a peer";
if (classFile.getSuperClassName().asIdentifier().equals("java.lang.Object"))
output.write("virtual ");
MetaClass superMetaClass = MetaClassFactory.getMetaClass(classFile.getSuperClassName()).proxy();
output.write("::" + superMetaClass.getFullyQualifiedName("::"));
// Now, add all of the interfaces that are implemented
for (TypeName i: classFile.getInterfaces())
{
MetaClass interfaceClass = MetaClassFactory.getMetaClass(i).proxy();
output.write(", public virtual ");
output.write("::" + interfaceClass.getFullyQualifiedName("::"));
}
output.write(newLine);
output.write("{" + newLine);
output.write("public: " + newLine);
output.write(newLine);
output.write("// Methods which must be implemented by the Developer" + newLine);
output.write("// --------------------------------------------------" + newLine);
output.write(newLine);
// Generate the native method declarations
Collection methods = classFile.getMethods();
for (ClassMethod method: methods)
{
if (!method.getAccessFlags().contains(MethodAccessFlag.NATIVE))
continue;
String methodName = method.getName();
if (methodName.equals("jaceCreateInstance") || methodName.equals("jaceDestroyInstance")
|| methodName.equals("jaceSetVm"))
{
continue;
}
if (!method.getAccessFlags().contains(MethodAccessFlag.STATIC))
proxyGen.generateMethodDeclaration(output, metaClass, method,
ProxyGenerator.InvokeStyle.VIRTUAL);
else
proxyGen.generateMethodDeclaration(output, metaClass, method,
ProxyGenerator.InvokeStyle.NORMAL);
output.write(newLine);
}
output.write(newLine);
output.write("// Methods made available by Jace" + newLine);
output.write("// ------------------------------" + newLine);
output.write(newLine);
// Generate non-native method declarations.
for (ClassMethod method: methods)
{
if (method.getAccessFlags().contains(MethodAccessFlag.NATIVE))
continue;
String methodName = method.getName();
if (methodName.equals("") || methodName.equals("") || methodName.equals(
"jaceUserStaticInit") || methodName.equals("jaceUserClose") || methodName.equals(
"jaceUserFinalize") || methodName.equals("jaceDispose") || methodName.equals(
"jaceSetNativeHandle") || methodName.equals("jaceGetNativeHandle"))
{
continue;
}
proxyGen.generateMethodDeclaration(output, metaClass, method, InvokeStyle.NORMAL);
output.write(newLine);
}
output.write(newLine);
Util.generateComment(output, "Returns the Java proxy.");
output.write("::" + metaClass.proxy().getFullyQualifiedName("::") + " getJaceProxy();" + newLine);
output.write(newLine);
output.write("// Fields made available by Jace" + newLine);
output.write("// -----------------------------" + newLine);
output.write(newLine);
proxyGen.generateFieldDeclarations(output, true);
output.write("// Methods internal to Jace" + newLine);
output.write("// ------------------------" + newLine);
output.write(newLine);
Util.generateComment(output, "Called when the VM instantiates a new " + name + ".");
output.write("explicit " + name + "(jobject);" + newLine);
output.write(newLine);
Util.generateComment(output, "Copy an existing reference.");
output.write(name + "(const " + name + "&);" + newLine);
output.write(newLine);
Util.generateComment(output, "Called when the the user explicitly collects a " + name + newLine
+ "or when the VM garbage collects a " + name + ".");
output.write("virtual ~" + name + "() throw ();" + newLine);
output.write(newLine);
output.write("virtual const JClass& getJavaJniClass() const throw (::jace::JNIException);"
+ newLine);
output.write("static const JClass& staticGetJavaJniClass() throw (::jace::JNIException);"
+ newLine);
output.write(newLine);
if (userDefinedMembers)
{
output.write("// User defined members" + newLine);
output.write("// --------------------" + newLine);
String userInclude = peerMetaClass.getPackage().toName("/", true) + peerMetaClass.
getSimpleName() + "_user.h";
output.write("#include \"" + userInclude + "\"" + newLine);
output.write(newLine);
}
output.write("};" + newLine);
output.write(newLine);
endNamespace(output);
output.write(peerMetaClass.endGuard() + newLine);
output.write(newLine);
}
/**
* Generates the C++ Peer source that is required to implement the non-native member functions of
* the Peer.
*
* @param output the output writer
* @throws IOException if an error occurs while writing
*/
private void generateCppPeerSource(Writer output) throws IOException
{
String fullName = metaClass.getFullyQualifiedTrueName(".");
Util.generateComment(output,
"This is the source for the implementation of the Jace Peer for " + fullName + "."
+ newLine + "Please do not edit this source. Any changes made will be overwritten."
+ newLine + newLine
+ "For more information, please refer to the Jace Developer's Guide.");
output.write(newLine);
ProxyGenerator generator = new ProxyGenerator.Builder(new ClassPath(System.getProperty(
"java.class.path")), classFile,
new ProxyGenerator.AcceptAll()).accessibility(AccessibilityType.PRIVATE).build();
generator.includeStandardSourceHeaders(output);
output.write(newLine);
Util.generateComment(output, "Class dependencies.");
for (MetaClass dependency: generator.getForwardDeclarations())
output.write(dependency.include() + newLine);
output.write(newLine);
output.write(metaClass.toPeer().include() + newLine);
output.write(newLine);
beginNamespace(output);
output.write(newLine);
output.write(generator.getInitializerValue(true) + newLine);
generator.generateMethodDefinitions(output, true);
generator.generateFieldDefinitions(output, true);
generator.generateJaceDefinitions(output, true);
endNamespace(output);
output.write(newLine);
}
/**
* Generates the mappings from native methods to C++ Peer member functions.
*
* @param output the output writer
* @throws IOException if an error occurs while writing
*/
private void generateCppPeerMappings(Writer output) throws IOException
{
String fullName = metaClass.getFullyQualifiedTrueName(".");
MetaClass peerMetaClass = metaClass.toPeer();
String fullPeerName = "::" + peerMetaClass.getFullyQualifiedName("::");
String className = mangleName(metaClass.getFullyQualifiedTrueName("/"));
Util.generateComment(output,
"These JNI mappings are for the Jace Peer for " + fullName + "." + newLine
+ "Please do not edit these JNI mappings. Any changes made will be overwritten."
+ newLine + newLine
+ "For more information, please refer to the Jace Developer's Guide.");
output.write(newLine);
ProxyGenerator proxyGen = new ProxyGenerator.Builder(new ClassPath(System.getProperty(
"java.class.path")), classFile,
new ProxyGenerator.AcceptAll()).accessibility(AccessibilityType.PRIVATE).build();
proxyGen.includeStandardHeaders(output, true);
output.write("#include \"" + JaceConstants.getProxyPackage().asPath()
+ "/java/lang/Throwable.h\"" + newLine);
output.write("#include \"" + JaceConstants.getProxyPackage().asPath()
+ "/java/lang/RuntimeException.h\"" + newLine);
output.write("#include \"" + JaceConstants.getProxyPackage().asPath() + "/java/lang/Class.h\""
+ newLine);
output.write("#include \"" + JaceConstants.getProxyPackage().asPath() + "/java/lang/String.h\""
+ newLine);
output.write("#include \"jace/Jace.h\"" + newLine);
output.write("#include \"jace/VirtualMachineRunningError.h\"" + newLine);
output.write("#include \"jace/VirtualMachineShutdownError.h\"" + newLine);
output.write(newLine);
Util.generateComment(output, "Class dependencies.");
for (MetaClass dependency: proxyGen.getForwardDeclarations())
output.write(dependency.include() + newLine);
output.write(newLine);
output.write(metaClass.toPeer().include() + newLine);
output.write(newLine);
output.write("#include " + newLine);
output.write("#include " + newLine);
output.write(newLine);
// generate the native method implementations
for (ClassMethod method: classFile.getMethods())
{
if (!method.getAccessFlags().contains(MethodAccessFlag.NATIVE))
continue;
String methodName = method.getName();
Util.generateComment(output, "The JNI mapping for" + newLine + newLine + "Class: "
+ mangleName(metaClass.getFullyQualifiedTrueName("/")) + newLine
+ "Method: " + method.getName() + newLine
+ "Signature: " + method.getDescriptor());
// treat jaceCreateInstance, jaceDestroyInstance, and jaceSetVm specially
if (methodName.equals("jaceCreateInstance"))
{
output.write("extern \"C\" JNIEXPORT jlong JNICALL ");
output.write("Java_" + className + "_jaceCreateInstance(JNIEnv *env, jobject jPeer)"
+ newLine);
output.write("{" + newLine);
output.write(" try" + newLine);
output.write(" {" + newLine);
output.write(" ::jace::Peer* peer = new " + fullPeerName + "(jPeer);" + newLine);
output.write(" peer->initialize(); " + newLine);
output.write(" return reinterpret_cast(peer);" + newLine);
output.write(" }" + newLine);
output.write(" catch (jace::proxy::java::lang::Throwable& t)" + newLine);
output.write(" {" + newLine);
output.write(" env->Throw(static_cast(env->NewLocalRef(static_cast(t))));"
+ newLine);
output.write(" ::jace::detach();" + newLine);
output.write(" return 0;" + newLine);
output.write(" }" + newLine);
output.write(" catch (std::exception& e)" + newLine);
output.write(" {" + newLine);
output.write(" std::string msg = std::string(\"[\") + __FILE__ + \":\" + "
+ "jace::toString(__LINE__) +" + newLine);
output.write(" \"] An unexpected JNI error has occurred: \" + "
+ "e.what();" + newLine);
output.write(" try" + newLine);
output.write(" {" + newLine);
output.write(" jace::proxy::java::lang::RuntimeException ex(jace::java_new(msg));"
+ newLine);
output.write(" env->Throw(static_cast(env->NewLocalRef(static_cast(ex))));"
+ newLine);
output.write(" ::jace::detach();" + newLine);
output.write(" }" + newLine);
output.write(" catch (jace::VirtualMachineShutdownError&)" + newLine);
output.write(" {" + newLine);
output.write(" std::cerr << msg << std::endl;" + newLine);
output.write(" }" + newLine);
output.write(" return 0;" + newLine);
output.write(" }" + newLine);
output.write("}" + newLine);
output.write(newLine);
continue;
}
else if (methodName.equals("jaceDestroyInstance"))
{
output.write("extern \"C\" JNIEXPORT void JNICALL ");
output.write("Java_" + className + "_jaceDestroyInstance(JNIEnv *env, jobject jPeer)"
+ newLine);
output.write("{" + newLine);
output.write(" try" + newLine);
output.write(" {" + newLine);
output.write(" jclass classId = env->GetObjectClass(jPeer);" + newLine);
output.write(" jfieldID fieldId = env->GetFieldID(classId, \"jaceNativeHandle\", \"J\");"
+ newLine);
output.write(" if (fieldId == 0)" + newLine);
output.write(" ::jace::catchAndThrow();" + newLine);
output.write(" jlong nativeHandle = env->GetLongField(jPeer, fieldId);" + newLine);
output.write(" ::jace::Peer* peer = reinterpret_cast<::jace::Peer*>(nativeHandle);"
+ newLine);
output.write(" peer->destroy();" + newLine);
output.write(" delete peer; " + newLine);
output.write(" }" + newLine);
output.write(" catch (std::exception& e)" + newLine);
output.write(" {" + newLine);
output.write(" std::cerr << std::string(\"[\") + __FILE__ + \":\" + "
+ "jace::toString(__LINE__) + " + newLine);
output.write(" \"] An unexpected JNI error has occurred: \" << e.what() "
+ "<< std::endl;" + newLine);
output.write(" }" + newLine);
output.write("}" + newLine);
output.write(newLine);
continue;
}
else if (methodName.equals("jaceSetVm"))
{
output.write("extern \"C\" JNIEXPORT void JNICALL ");
output.write("Java_" + className + "_jaceSetVm(JNIEnv *env, jclass)" + newLine);
output.write("{" + newLine);
output.write(" try" + newLine);
output.write(" {" + newLine);
output.write(" if (!::jace::getJavaVm())" + newLine);
output.write(" {" + newLine);
output.write(" JavaVM* jvm;" + newLine);
output.write(" jint result = env->GetJavaVM(&jvm);" + newLine);
output.write(newLine);
output.write(" if (result != 0)" + newLine);
output.write(" {" + newLine);
output.write(" std::string msg = std::string(\"" + className
+ " ::jaceSetVm\\n\") + " + newLine);
output.write(" \"Unable to retrieve the JVM from the JNIEnv* object. The specific JNI error code is \" +"
+ newLine);
output.write(" ::jace::toString(result);" + newLine);
output.write(" throw ::jace::JNIException(msg);" + newLine);
output.write(" }" + newLine);
output.write(" ::jace::setJavaVm(jvm);" + newLine);
output.write(" }" + newLine);
output.write(newLine);
output.write(" }" + newLine);
output.write(" catch (jace::VirtualMachineRunningError&)" + newLine);
output.write(" {" + newLine);
output.write(" return; // the VM is already set, we're done" + newLine);
output.write(" }" + newLine);
output.write(" catch (std::exception& e)" + newLine);
output.write(" {" + newLine);
output.write(" std::cerr << std::string(\"[\") + __FILE__ + \":\" + "
+ "jace::toString(__LINE__) +" + newLine);
output.write(" \"] An unexpected JNI error has occurred: \" << e.what() "
+ "<< std::endl;" + newLine);
output.write(" return;" + newLine);
output.write(" }" + newLine);
output.write("}" + newLine);
output.write(newLine);
output.write(newLine);
output.write(newLine);
continue;
}
// now, handle the normal case
String functionName = getNativeMethodName(metaClass, method);
MetaClass returnType = MetaClassFactory.getMetaClass(method.getReturnType()).proxy();
boolean isStatic = method.getAccessFlags().contains(MethodAccessFlag.STATIC);
List parameterTypes = method.getParameterTypes();
Collection params = Lists.newArrayListWithCapacity(1 + parameterTypes.size());
if (isStatic)
params.add("jclass jP0");
else
params.add("jobject jP0");
int parameterIndex = 1;
for (TypeName param: parameterTypes)
{
MetaClass paramClass = MetaClassFactory.getMetaClass(param).proxy();
params.add(paramClass.getJniType() + " jP" + parameterIndex);
++parameterIndex;
}
output.write("extern \"C\" JNIEXPORT " + returnType.getJniType() + " JNICALL " + functionName);
output.write("(JNIEnv* env, ");
output.write(new DelimitedCollection(params).toString(", "));
output.write(") { " + newLine);
output.write(newLine);
output.write(" try" + newLine);
output.write(" {" + newLine);
// define the Jace Proxy version of the parameters
String target;
if (!isStatic)
{
output.write(" " + fullPeerName + "* peer = dynamic_cast< " + fullPeerName
+ "*>(::jace::getPeer(jP0));" + newLine);
output.write(" assert(peer!=0);" + newLine);
target = "peer->";
}
else
target = fullPeerName + "::";
parameterIndex = 1;
for (TypeName param: parameterTypes)
{
MetaClass paramClass = MetaClassFactory.getMetaClass(param).proxy();
output.write(" " + "::" + paramClass.getFullyQualifiedName("::"));
output.write(" p" + parameterIndex + "(jP" + parameterIndex + ");" + newLine);
++parameterIndex;
}
if (parameterTypes.size() > 0 || !isStatic)
output.write(newLine);
if (returnType instanceof VoidClass)
{
output.write(" " + target + methodName + "(");
for (int i = 0; i < params.size() - 1; ++i)
{
output.write("p" + (i + 1));
if (i < params.size() - 2)
output.write(",");
output.write(" ");
}
output.write(");" + newLine);
output.write(" return;" + newLine);
}
else
{
output.write(" return ");
if (!returnType.isPrimitive())
output.write("static_cast<" + returnType.getJniType() + ">(env->NewLocalRef(");
output.write(target + methodName + "(");
for (int i = 0; i < params.size() - 1; ++i)
{
output.write("p" + (i + 1));
if (i < params.size() - 2)
output.write(", ");
}
output.write(")");
if (!returnType.isPrimitive())
output.write("))");
output.write(";" + newLine);
}
output.write(" }" + newLine);
String returnValue = returnType instanceof VoidClass ? "" : " NULL";
output.write(" catch (jace::proxy::java::lang::Throwable& t)" + newLine);
output.write(" {" + newLine);
output.write(" env->Throw(static_cast(env->NewLocalRef(static_cast(t))));"
+ newLine);
output.write(" ::jace::detach();" + newLine);
output.write(" return" + returnValue + ";" + newLine);
output.write(" }" + newLine);
output.write(" catch (std::exception& e)" + newLine);
output.write(" {" + newLine);
output.write(" std::string msg = std::string(\"[\") + __FILE__ + \":\" + "
+ "jace::toString(__LINE__) + " + newLine);
output.write(" \"] An unexpected JNI error has occurred: \" + "
+ "e.what();" + newLine);
output.write(" try" + newLine);
output.write(" {" + newLine);
output.write(" jace::proxy::java::lang::RuntimeException ex(jace::java_new(msg));"
+ newLine);
output.write(" env->Throw(static_cast(env->NewLocalRef(static_cast(ex))));"
+ newLine);
output.write(" ::jace::detach();" + newLine);
output.write(" }" + newLine);
output.write(" catch (jace::VirtualMachineShutdownError&)" + newLine);
output.write(" {" + newLine);
output.write(" std::cerr << msg << std::endl;" + newLine);
output.write(" }" + newLine);
output.write(" return" + returnValue + ";" + newLine);
output.write(" }" + newLine);
output.write("}" + newLine);
output.write(newLine);
}
}
/**
* Generates the appropriate C function name for the native method.
*
* Note: There are two forms of native method names: short, which is the simple method, and long,
* which is used in the presence of overloading. This method always returns the long form of the
* method name which includes the argument signature, as it should always work - with or without
* the presence of overloading.
*
* @param metaClass the class
* @param method the method
* @return the C++ function name
*/
private String getNativeMethodName(ClassMetaClass metaClass, ClassMethod method)
{
List parameterTypes = method.getParameterTypes();
StringBuilder nativeName = new StringBuilder("Java_");
String mangledClassName = mangleName(metaClass.getFullyQualifiedTrueName("/"));
String mangledMethodName = mangleName(method.getName());
nativeName.append(mangledClassName);
nativeName.append("_");
nativeName.append(mangledMethodName);
nativeName.append("__");
for (Iterator it = parameterTypes.iterator(); it.hasNext();)
{
String type = it.next().asDescriptor();
// If this is a class type, make sure it ends with a semi-colon.
if (type.startsWith("L") && !(type.charAt(type.length() - 1) == ';'))
type += ";";
type = mangleName(type);
nativeName.append(type);
}
return nativeName.toString();
}
/**
* Converts a Java class name into a legal C++ name.
*
* @param name the Java class name
* @return the C++ class name
*/
@SuppressWarnings("AssignmentToForLoopParameter")
private String mangleName(String name)
{
StringBuilder newName = new StringBuilder(name);
for (int i = 0; i < newName.length(); ++i)
{
char c = newName.charAt(i);
if (c == '/')
newName.replace(i, i + 1, "_");
else if (c == '_')
{
newName.replace(i, i + 1, "_1");
++i;
}
else if (c == ';')
{
newName.replace(i, i + 1, "_2");
++i;
}
else if (c == '[')
{
newName.replace(i, i + 1, "_3");
++i;
}
else if (!(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9')))
{
StringBuilder unicodeRepresentation = new StringBuilder(Integer.toHexString(c));
while (unicodeRepresentation.length() < 5)
unicodeRepresentation.insert(0, '0');
unicodeRepresentation.insert(0, '_');
newName.replace(i, i + 1, unicodeRepresentation.toString());
++i;
}
}
return newName.toString();
}
/**
* Opens the namespace block.
*
* @param output the output writer
* @throws IOException if an error occurs while writing
*/
private void beginNamespace(Writer output) throws IOException
{
ClassPackage classPackage = metaClass.toPeer().getPackage();
StringBuilder namespace = new StringBuilder("BEGIN_NAMESPACE_");
namespace.append(classPackage.getPath().size());
namespace.append("(");
namespace.append(classPackage.toName(", ", false));
namespace.append(")");
output.write(namespace + newLine);
}
/**
* Closes the namespace block.
*
* @param output the output writer
* @throws IOException if an error occurs while writing
*/
private void endNamespace(Writer output) throws IOException
{
ClassPackage classPackage = metaClass.toPeer().getPackage();
StringBuilder namespace = new StringBuilder("END_NAMESPACE_");
namespace.append(classPackage.getPath().size());
namespace.append("(");
namespace.append(classPackage.toName(", ", false));
namespace.append(")");
output.write(namespace + newLine);
}
/**
* Returns the logger associated with the object.
*
* @return the logger associated with the object
*/
private Logger getLogger()
{
return log;
}
/**
* Returns a String describing the usage of this tool.
*
* @return String describing the usage of this tool
*/
private static String getUsage()
{
return "Usage: PeerGenerator " + newLine
+ " " + newLine
+ "" + newLine;
}
@SuppressWarnings("UseOfSystemOutOrSystemErr")
public static void main(String[] args)
{
if (args.length != 4)
{
System.out.println(getUsage());
return;
}
File classFile = new File(args[0]);
File includeDir = new File(args[1]);
File sourceDir = new File(args[2]);
boolean userDefinedMembers = Boolean.valueOf(args[3]).booleanValue();
PeerGenerator generator = new PeerGenerator(new ClassFile(classFile), classFile.lastModified(),
includeDir, sourceDir, userDefinedMembers);
Logger log = generator.getLogger();
log.info("Beginning Peer generation.");
try
{
generator.generate();
}
catch (IOException e)
{
log.error("", e);
}
log.info("Finished Peer generation.");
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy