/*
* Copyright 2013, We The Internet Ltd.
*
* All rights reserved.
*
* Distributed under a modified BSD License as follow:
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution, unless otherwise
* agreed to in a written document signed by a director of We The Internet Ltd.
*
* Neither the name of We The Internet nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package xapi.dev.source;
public class SourceBuilder<Payload> implements CanAddImports {
protected class SourceBuilderImports extends ImportSection implements HasPackage {
@Override
public String getPackageName() {
return SourceBuilder.this.getPackage();
}
}
public enum JavaType {
CLASS("class"),
INTERFACE("interface"),
ENUM("enum"),
ANNOTATION("@interface"),
UNKNOWN("");
private final String keyword;
JavaType(String keyword) {
this.keyword = keyword;
}
public void initialize(SourceBuilder builder, String pkg, String filename) {
builder.setClassDefinition("public " + keyword + " " + filename, false);
builder.setPackage(pkg);
}
}
private final PrintBuffer head;
private PrintBuffer buffer;
private SourceBuilderImports imports;
private ClassBuffer classDef;
private Payload payload;
private String pkgName = "";
private int skip;
public SourceBuilder() {
head = buffer = new PrintBuffer();
}
public SourceBuilder(Payload payload) {
this();
setPayload(payload);
}
public SourceBuilder(String classDef) {
this();
setClassDefinition(classDef, classDef.trim().endsWith("{"));
}
public PrintBuffer getBuffer() {
return buffer;
}
public ClassBuffer getClassBuffer() {
if (classDef == null) {
throw new TypeDefinitionException(
"setClassDefinition() has not been called yet.\n"
+ "If you are running the template generator, your template "
+ "does include a //@classDefinition()// declaration,\n"
+ "or your generator is attempting to access the class "
+ "definition before it is parsed.");
}
return classDef;
}
public SourceBuilder<Payload> setClassDefinition(String definition,
boolean wellFormatted) {
if (classDef == null) {
// make sure import buffer comes before class def
getImports();
classDef = new ClassBuffer(this).indent();
// create a new print buffer for content after class definition
head.addToEnd(classDef);
head.setNotIndent();
addBuffer(new PrintBuffer());
}
classDef.setDefinition(definition, wellFormatted);
return this;
}
public ImportSection getImports() {
if (imports == null) {
imports = new SourceBuilderImports();
}
return imports;
}
public Payload getPayload() {
return payload;
}
protected SourceBuilder<Payload> addBuffer(PrintBuffer newBuffer) {
if (newBuffer == buffer) {
return this;
}
head.addToEnd(newBuffer);
head.setNotIndent();
buffer = newBuffer;
return this;
}
public SourceBuilder<Payload> setPayload(Payload payload) {
this.payload = payload;
return this;
}
public String getPackage() {
return pkgName;
}
public SourceBuilder<Payload> setPackage(String pkgName) {
if (pkgName.endsWith(";")) {
pkgName = pkgName.substring(0, pkgName.length() - 1);
}
if (pkgName.startsWith("package ")) {
pkgName = pkgName.substring(8);
}
this.pkgName = pkgName;
return this;
}
public SourceBuilder<Payload> addImports(Class<?>... cls) {
getImports().addImports(cls);
return this;
}
public SourceBuilder<Payload> addImports(String... cls) {
getImports().addImports(cls);
return this;
}
public SourceBuilder<Payload> addInterfaces(Class<?>... cls) {
getClassBuffer().addInterfaces(cls);
return this;
}
public SourceBuilder<Payload> addInterfaces(String... cls) {
getClassBuffer().addInterfaces(cls);
return this;
}
public SourceBuilder<Payload> setSuperClass(Class<?> cls) {
getClassBuffer().setSuperClass(cls);
return this;
}
public SourceBuilder<Payload> setSuperClass(String cls) {
getClassBuffer().setSuperClass(cls);
return this;
}
public SourceBuilder<Payload> setLinesToSkip(int i) {
this.skip = i;
return this;
}
public int getLinesToSkip() {
try {
return skip;
} finally {
skip = 0;
}
}
@Override
public final String toString() {
return toSource();
}
public String toSource() {
StringBuilder source = new StringBuilder();
String body = head.toSource();
if (pkgName.length() > 0) {
if (body.trim().startsWith("package")) {
int ind = body.indexOf(';', body.indexOf("package"));
body = body.substring(ind + 1);
}
source.append("package " + pkgName + ";\n\n");
}
if (imports != null) {
source.append(imports.toSource());
}
source.append(body);
return source.toString();
}
public String getQualifiedName() {
return getClassBuffer().getQualifiedName();
}
public String getSourceFileName() {
final String pkg = getPackage();
if (pkg.length() == 0) {
return getSimpleName() + ".java";
}
return pkg.replace('.', '/') + "/" + getSimpleName() + ".java";
}
public String getClassFileName() {
final String pkg = getPackage();
if (pkg.length() == 0) {
return getSimpleName() + ".class";
}
return pkg.replace('.', '/') + "/" + getSimpleName() + ".class";
}
public String getSimpleName() {
return getClassBuffer().getSimpleName();
}
public void destroy() {
setPayload(null);
head.tail = null;
head.head = null;
buffer = null;
imports = null;
classDef = null;
}
public boolean isDefined() {
return classDef != null;
}
}