/*
* Copyright 2011 cruxframework.org.
*
* 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.cruxframework.crux.core.rebind;
import java.util.ArrayList;
import java.util.List;
import org.cruxframework.crux.core.rebind.context.RebindContext;
import com.google.gwt.core.ext.CachedGeneratorResult;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JParameter;
import com.google.gwt.core.ext.typeinfo.JRealClassType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.dev.generator.NameFactory;
import com.google.gwt.user.rebind.SourceWriter;
/**
* @author Thiago da Rosa de Bustamante
*
*/
public abstract class AbstractProxyCreator
{
protected RebindContext context;
protected boolean cacheable;
/**
* @param logger
* @param context
* @param crossDocumentIntf
*/
public AbstractProxyCreator(RebindContext context, boolean cacheable)
{
this.context = context;
this.cacheable = cacheable;
}
protected boolean isAlreadyGenerated(String className)
{
return context.getGeneratorContext().getTypeOracle().findType(className) != null;
}
/**
* Creates the proxy.
*
* @return a proxy class name .
* @throws CruxGeneratorException
*/
public String create() throws CruxGeneratorException
{
String className = getProxyQualifiedName();
if (this.cacheable)
{
if (findCacheableImplementationAndMarkForReuseIfAvailable())
{
return className;
}
}
if (isAlreadyGenerated(className))
{
return className;
}
SourcePrinter printer = getSourcePrinter();
if (printer == null)
{
return className;
}
generateSubTypes(printer);
generateProxyContructor(printer);
generateProxyMethods(printer);
generateProxyFields(printer);
generateProxyResources();
printer.commit();
return className;
}
/**
*
*/
protected void generateProxyResources()
{
}
/**
* @param srcWriter
*/
protected void generateLoggerField(SourcePrinter srcWriter)
{
srcWriter.println("private static Logger _logger_ = Logger.getLogger("+getProxySimpleName()+".class.getName());");
}
/**
* Generate the proxy constructor and delegate to the superclass constructor
* using the default address for the
* {@link com.google.gwt.user.client.rpc.RemoteService RemoteService}.
*/
protected void generateProxyContructor(SourcePrinter srcWriter) throws CruxGeneratorException
{
}
/**
* Generate any fields required by the proxy.
* @throws CruxGeneratorException
*/
protected void generateProxyFields(SourcePrinter srcWriter) throws CruxGeneratorException
{
}
/**
* @param srcWriter
* @param serializableTypeOracle
* @throws CruxGeneratorException
*/
protected void generateProxyMethods(SourcePrinter srcWriter) throws CruxGeneratorException
{
}
/**
* Override this method to generate any nested type required by the proxy
* @param srcWriter
* @throws CruxGeneratorException
*/
protected void generateSubTypes(SourcePrinter srcWriter) throws CruxGeneratorException
{
}
/**
* @param sourcePrinter
* @param message
*/
protected void logDebugMessage(SourcePrinter sourcePrinter, String message)
{
sourcePrinter.println("if (LogConfiguration.loggingIsEnabled()){");
sourcePrinter.println("_logger_.log(Level.INFO, "+message+");");
sourcePrinter.println("}");
}
/**
* @param method
* @return
*/
protected String getJsniSimpleSignature(JMethod method)
{
StringBuilder sb = new StringBuilder();
sb.append(method.getName());
sb.append("(");
for (JParameter param : method.getParameters())
{
sb.append(param.getType().getJNISignature());
}
sb.append(")");
return sb.toString();
}
/**
* @return the full qualified name of the proxy object.
*/
public abstract String getProxyQualifiedName();
/**
* @return the simple name of the proxy object.
*/
public abstract String getProxySimpleName();
/**
* @return a sourceWriter for the proxy class
*/
protected abstract SourcePrinter getSourcePrinter();
/**
* @param w
* @param nameFactory
* @param method
*/
protected void generateMethodParameters(SourcePrinter w, NameFactory nameFactory, JMethod method)
{
boolean needsComma = false;
JParameter[] params = method.getParameters();
for (int i = 0; i < params.length; ++i)
{
JParameter param = params[i];
if (needsComma)
{
w.print(", ");
}
else
{
needsComma = true;
}
JType paramType = param.getType();
paramType = paramType.getErasedType();
w.print(paramType.getQualifiedSourceName());
w.print(" ");
String paramName = param.getName();
nameFactory.addName(paramName);
w.print(paramName);
}
}
/**
* @param w
* @param methodThrows
*/
protected void generateMethodTrhowsClause(SourcePrinter w, JMethod method)
{
boolean needsComma = false;
JType[] methodThrows = method.getThrows();
if (methodThrows != null)
for (JType methodThrow : methodThrows)
{
if (needsComma)
{
w.print(", ");
}
else
{
w.print(" throws ");
needsComma = true;
}
JType throwType = methodThrow.getErasedType();
w.print(throwType.getQualifiedSourceName());
}
}
/**
* @param srcWriter
* @param method
* @param returnType
* @return
*/
protected List<JParameter> generateProxyWrapperMethodDeclaration(SourcePrinter srcWriter, JMethod method)
{
srcWriter.println();
srcWriter.print("public void ");
srcWriter.print(method.getName() + "(");
boolean needsComma = false;
List<JParameter> parameters = new ArrayList<JParameter>();
JParameter[] params = method.getParameters();
for (int i = 0; i < params.length; ++i)
{
JParameter param = params[i];
if (needsComma)
{
srcWriter.print(", ");
}
else
{
needsComma = true;
}
JType paramType = param.getType();
if (i == (params.length - 1))
{
srcWriter.print("final ");
}
srcWriter.print(paramType.getParameterizedQualifiedSourceName());
srcWriter.print(" ");
String paramName = param.getName();
parameters.add(param);
srcWriter.print(paramName);
}
srcWriter.println(") {");
return parameters;
}
/**
* @return
*/
protected boolean findCacheableImplementationAndMarkForReuseIfAvailable()
{
return false;
}
protected boolean findCacheableImplementationAndMarkForReuseIfAvailable(JClassType baseIntf)
{
CachedGeneratorResult lastResult = context.getGeneratorContext().getCachedGeneratorResult();
if (lastResult == null || !context.getGeneratorContext().isGeneratorResultCachingEnabled())
{
return false;
}
String proxyName = getProxyQualifiedName();
// check that it is available for reuse
if (!lastResult.isTypeCached(proxyName))
{
return false;
}
try
{
long lastModified = 0L;
if (baseIntf instanceof JRealClassType)
{
lastModified = ((JRealClassType)baseIntf).getLastModifiedTime();
}
if (lastModified != 0L && lastModified < lastResult.getTimeGenerated())
{
return context.getGeneratorContext().tryReuseTypeFromCache(proxyName);
}
}
catch (RuntimeException ex)
{
// could get an exception checking modified time
return false;
}
return false;
}
protected boolean isCacheable()
{
return cacheable;
}
/**
* Printer for screen creation codes.
*
* @author Thiago da Rosa de Bustamante
*/
public static interface SourcePrinter
{
/**
* Flushes the printed code into a real output (file).
*/
void commit();
/**
* Indents the next line to be printed
*/
void indent();
/**
* Outdents the next line to be printed
*/
void outdent();
/**
* Prints an in-line code.
* @param s
*/
void print(String s);
/**
* Prints a line of code into the output.
* <li>If the line ends with <code>"{"</code>, indents the next line.</li>
* <li>If the line ends with <code>"}"</code>, <code>"};"</code> or <code>"});"</code>, outdents the next line.</li>
* @param s
*/
void println(String s);
void println();
}
public static class SourceCodePrinter implements SourcePrinter
{
private final TreeLogger logger;
private final SourceWriter srcWriter;
/**
* Constructor
* @param srcWriter
* @param logger
*/
public SourceCodePrinter(SourceWriter srcWriter, TreeLogger logger)
{
this.srcWriter = srcWriter;
this.logger = logger;
}
@Override
public void commit()
{
srcWriter.commit(logger);
}
@Override
public void indent()
{
srcWriter.indent();
}
@Override
public void outdent()
{
srcWriter.outdent();
}
@Override
public void print(String s)
{
srcWriter.print(s);
}
@Override
public void println(String s)
{
String line = s.trim();
if (line.endsWith("}") || line.endsWith("});") || line.endsWith("};") || line.endsWith("}-*/;") || line.startsWith("}"))
{
outdent();
}
srcWriter.println(s);
if (line.endsWith("{"))
{
indent();
}
}
@Override
public void println()
{
srcWriter.println();
}
}
}