/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openflexo.foundation.dm;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.Map;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openflexo.foundation.DataModification;
import org.openflexo.foundation.FlexoObservable;
import org.openflexo.foundation.Inspectors;
import org.openflexo.foundation.dm.DMEntity.DMTypeVariable;
import org.openflexo.foundation.dm.dm.DMAttributeDataModification;
import org.openflexo.foundation.dm.dm.DMEntityClassNameChanged;
import org.openflexo.foundation.dm.dm.DMMethodNameChanged;
import org.openflexo.foundation.dm.dm.EntityDeleted;
import org.openflexo.foundation.dm.dm.MethodDeleted;
import org.openflexo.foundation.dm.javaparser.MethodSourceCode;
import org.openflexo.foundation.dm.javaparser.ParsedJavaMethod;
import org.openflexo.foundation.dm.javaparser.ParsedJavadoc;
import org.openflexo.foundation.dm.javaparser.ParsedJavadocItem;
import org.openflexo.foundation.dm.javaparser.ParserNotInstalledException;
import org.openflexo.foundation.dm.javaparser.SourceCodeOwner;
import org.openflexo.foundation.xml.FlexoDMBuilder;
import org.openflexo.localization.FlexoLocalization;
import org.openflexo.toolbox.StringUtils;
import org.openflexo.toolbox.ToolBox;
/**
* Represents a method (aka action or execution primitive) related to an entity
*
* @author sguerin
*
*/
public class DMMethod extends DMObject implements Typed, DMGenericDeclaration, DMTypeOwner, DMMember, SourceCodeOwner {
static final Logger logger = Logger.getLogger(DMMethod.class.getPackage().getName());
private static final String VOID_DEFAULT_CODE = " //TODO: Implement this method";
private static final String DOUBLE_DEFAULT_CODE = " //TODO: Implement this method" + StringUtils.LINE_SEPARATOR + " return 0.0d;";
private static final String FLOAT_DEFAULT_CODE = " //TODO: Implement this method" + StringUtils.LINE_SEPARATOR + " return 0.0f;";
private static final String INT_DEFAULT_CODE = " //TODO: Implement this method" + StringUtils.LINE_SEPARATOR + " return 0;";
private static final String CHAR_DEFAULT_CODE = " //TODO: Implement this method" + StringUtils.LINE_SEPARATOR + " return ' ';";
private static final String BOOLEAN_DEFAULT_CODE = " //TODO: Implement this method" + StringUtils.LINE_SEPARATOR
+ " return false;";
private static final String DEFAULT_CODE = " //TODO: Implement this method" + StringUtils.LINE_SEPARATOR + " return null;";
private static final String COMPILED_CODE = " /* compiled code not available */";
private static final String COMPILED_CODE_IN_JAVADOC = "< compiled code >";
// ==========================================================================
// ============================= Instance variables =========================
// ==========================================================================
protected String name;
private DMType _returnType;
private Vector<DMMethodParameter> _parameters;
private String _signatureNFQ = null;
private String _signatureFQ = null;
private String _parameterListAsString = null;
private String _parameterListAsStringFQ = null;
String _parameterNamedListAsString = null;
private DMVisibilityType _visibilityModifier;
private boolean isStatic;
private boolean isAbstract;
private boolean isSynchronized;
protected DMEntity entity;
private boolean _isStaticallyDefinedInTemplate = false;
// ==========================================================================
// ============================= Constructor ================================
// ==========================================================================
/**
* Constructor used during deserialization
*/
public DMMethod(FlexoDMBuilder builder) {
this(builder.dmModel);
initializeDeserialization(builder);
}
/**
* Default constructor
*/
public DMMethod(DMModel dmModel) {
super(dmModel);
_parameters = new Vector<DMMethodParameter>();
_visibilityModifier = DMVisibilityType.PUBLIC;
}
/**
* Constructor used for dynamic creation
*/
public DMMethod(DMModel dmModel, String name) {
this(dmModel);
this.name = name;
entity = null;
_returnType = null;
}
@Override
public void finalizeDeserialization(Object builder) {
_isRegistered = true;
preventFromModifiedPropagation();
try {
updateSignature();
} catch (DuplicateMethodSignatureException e) {
logger.warning("Unexpected DuplicateMethodSignatureException for " + this);
}
updateCode();
allowModifiedPropagation();
super.finalizeDeserialization(builder);
}
/**
* Update this property given an other property. This method updates only data extracted from LoadableDMEntity features and exclude many
* properties such as description.
*
* @throws DuplicateMethodSignatureException
*/
public void update(DMMethod method, boolean updateDescription) throws DuplicateMethodSignatureException {
if (getEntity() != null && getEntity().getMethod(method.getSignature()) != null
&& getEntity().getMethod(method.getSignature()) != this) {
throw new DuplicateMethodSignatureException(method.getSignature());
}
if (logger.isLoggable(Level.FINE)) {
logger.fine("Update " + getSignature() + " with " + method.getSignature());
}
String oldSignature = _getRegisteredWithSignature(); // getSignature();
if (logger.isLoggable(Level.FINE)) {
logger.fine("Old signature was: " + oldSignature);
}
// Name is supposed to be the same, but check anyway
if (!getName().equals(method.getName())) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Update name");
}
setName(method.getName());
} else {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Name is up-to-date");
}
}
// Type
if (getReturnType() == null || !getReturnType().equals(method.getReturnType())) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Update ReturnType");
}
setType(method.getReturnType());
} else {
if (logger.isLoggable(Level.FINE)) {
logger.fine("ReturnType is up-to-date");
}
}
// Visibility modifier
if (!getVisibilityModifier().equals(method.getVisibilityModifier())) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Update VisibilityModifier");
}
setVisibilityModifier(method.getVisibilityModifier());
} else {
if (logger.isLoggable(Level.FINE)) {
logger.fine("VisibilityModifier is up-to-date");
}
}
// IsAbstract
if (getIsAbstract() != method.getIsAbstract()) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Update IsAbstract");
}
setIsAbstract(method.getIsAbstract());
} else {
if (logger.isLoggable(Level.FINE)) {
logger.fine("IsAbstract is up-to-date");
}
}
// IsStatic
if (getIsStatic() != method.getIsStatic()) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Update IsStatic");
}
setIsStatic(method.getIsStatic());
} else {
if (logger.isLoggable(Level.FINE)) {
logger.fine("IsStatic is up-to-date");
}
}
// IsSynchronized
if (getIsSynchronized() != method.getIsSynchronized()) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Update IsSynchronized");
}
setIsSynchronized(method.getIsSynchronized());
} else {
if (logger.isLoggable(Level.FINE)) {
logger.fine("IsSynchronized is up-to-date");
}
}
// Parameters
if (logger.isLoggable(Level.FINER)) {
logger.finer("Before updating parameters, signature is " + getSignature());
}
Vector<DMMethodParameter> paramsToRemove = new Vector<DMMethodParameter>();
paramsToRemove.addAll(getParameters());
int index = 0;
for (DMMethodParameter param : (Vector<DMMethodParameter>) method.getParameters().clone()) {
// DMMethodParameter existingParam = getDMParameter(param.getName());
DMMethodParameter existingParam = index < getParameters().size() ? getParameters().elementAt(index) : null;
if (existingParam != null) {
// Update param
if (logger.isLoggable(Level.FINER)) {
logger.finer("Update param " + existingParam.getName());
}
existingParam.update(param, updateDescription);
paramsToRemove.remove(existingParam);
} else {
if (logger.isLoggable(Level.FINER)) {
logger.finer("Add param " + param.getName());
}
addToParametersNoCheck(param);
}
index++;
}
for (DMMethodParameter paramToRemove : paramsToRemove) {
if (logger.isLoggable(Level.FINER)) {
logger.finer("Remove param " + paramToRemove.getName());
}
removeFromParametersNoCheck(paramToRemove);
}
if (logger.isLoggable(Level.FINER)) {
logger.finer("After updating parameters, signature is " + getSignature());
}
// Code
try {
// logger.info("method.getSourceCode().getCode()=["+method.getSourceCode().getCode()+"]");
if (getSourceCode().getCode() == null && method.getSourceCode().getCode() != null) {
getSourceCode().setCode(method.getSourceCode().getCode(), false);
}
if (getSourceCode().getCode() != null && !getSourceCode().getCode().equals(method.getSourceCode().getCode())) {
getSourceCode().setCode(method.getSourceCode().getCode(), false);
}
} catch (ParserNotInstalledException e) {
e.printStackTrace();
}
// Descriptions
if (updateDescription) {
if (getDescription() == null && method.getDescription() != null || getDescription() != null
&& !getDescription().equals(method.getDescription())) {
setDescription(method.getDescription());
}
for (String descriptionKey : method.getSpecificDescriptions().keySet()) {
String description = method.getSpecificDescriptionForKey(descriptionKey);
if (description == null && getSpecificDescriptionForKey(descriptionKey) != null || description != null
&& !description.equals(getSpecificDescriptionForKey(descriptionKey))) {
setSpecificDescriptionsForKey(description, descriptionKey);
}
}
}
if (getEntity() != null && !getSignature().equals(oldSignature)) {
/*
* if (getEntity().getMethod(getSignature()) != null) { throw new DuplicateMethodSignatureException(getSignature()); } else {
*/
if (oldSignature != null) {
getEntity().removeMethodWithKey(oldSignature);
}
getEntity().setMethodForKey(this, getSignature());
// }
}
if (logger.isLoggable(Level.FINE)) {
logger.fine("Update " + getSignature() + " with " + method.getSignature() + " DONE");
}
}
/**
* Overrides allowModifiedPropagation
*
* @see org.openflexo.foundation.dm.DMObject#allowModifiedPropagation()
*/
@Override
public void allowModifiedPropagation() {
super.allowModifiedPropagation();
for (DMMethodParameter param : _parameters) {
param.allowModifiedPropagation();
}
}
@Override
public void setIsModified() {
if (ignoreNotifications()) {
return;
}
super.setIsModified();
if (getEntity() != null) {
getEntity().setIsModified();
}
}
@Override
public void delete() {
isDeleted = true;
setReturnType(null, false);
getEntity().unregisterMethod(this);
setChanged();
notifyObservers(new MethodDeleted(this));
name = null;
entity = null;
_returnType = null;
_parameters.clear();
_parameters = null;
super.delete();
deleteObservers();
}
@Override
public boolean isDeletable() {
if (getEntity() == null) {
return true;
}
return !getIsReadOnly() && !getEntity().getIsReadOnly();
}
@Override
public String getFullyQualifiedName() {
if (getEntity() != null) {
return getEntity().getFullyQualifiedName() + "." + getSignature();
}
return "NULL." + name;
}
@Override
public void setDescription(String aDescription) {
super.setDescription(aDescription);
updateCode();
}
@Override
public void setSpecificDescriptionsForKey(String description, String key) {
super.setSpecificDescriptionsForKey(description, key);
updateCode();
}
public String getSimplifiedSignature() {
if (_signatureNFQ == null) {
StringBuffer signature = new StringBuffer();
signature.append(name);
signature.append("(");
signature.append(getParameterListAsString(false));
signature.append(")");
_signatureNFQ = signature.toString();
}
return _signatureNFQ;
}
public String getSignature() {
if (_signatureFQ == null) {
StringBuffer signature = new StringBuffer();
signature.append(name);
signature.append("(");
signature.append(getParameterListAsString(true));
signature.append(")");
_signatureFQ = signature.toString();
}
return _signatureFQ;
}
public String getSimplifiedSignatureInContext(DMType context) {
StringBuffer signature = new StringBuffer();
signature.append(name);
signature.append("(");
signature.append(getParameterListAsStringInContext(context, false));
signature.append(")");
return signature.toString();
}
public String getSignatureInContext(DMType context) {
StringBuffer signature = new StringBuffer();
signature.append(name);
signature.append("(");
signature.append(getParameterListAsStringInContext(context, true));
signature.append(")");
return signature.toString();
}
public String getParameterListAsString(boolean fullyQualified) {
String _searched = fullyQualified ? _parameterListAsStringFQ : _parameterListAsString;
if (_searched == null) {
StringBuffer returned = new StringBuffer();
boolean isFirst = true;
if (_parameters != null && _parameters.size() > 0) {
for (Enumeration en = _parameters.elements(); en.hasMoreElements();) {
DMMethodParameter next = (DMMethodParameter) en.nextElement();
String typeName = "";
if (next.getType() != null) {
typeName = fullyQualified ? next.getType().getStringRepresentation() : next.getType()
.getSimplifiedStringRepresentation();
}
returned.append((isFirst ? "" : ",") + typeName);
isFirst = false;
}
}
if (fullyQualified) {
_parameterListAsStringFQ = returned.toString();
} else {
_parameterListAsString = returned.toString();
}
}
return fullyQualified ? _parameterListAsStringFQ : _parameterListAsString;
}
// Warning: no cache for this method
String getParameterListAsStringInContext(DMType context, boolean fullyQualified) {
if (_parameters == null) {
return "";
}
StringBuffer returned = new StringBuffer();
boolean isFirst = true;
for (Enumeration en = _parameters.elements(); en.hasMoreElements();) {
DMMethodParameter next = (DMMethodParameter) en.nextElement();
String typeName = "";
DMType typeInContext = DMType.makeInstantiatedDMType(next.getType(), context);
if (typeInContext != null) {
typeName = fullyQualified ? typeInContext.getStringRepresentation() : typeInContext.getSimplifiedStringRepresentation();
}
returned.append((isFirst ? "" : ",") + typeName);
isFirst = false;
}
return returned.toString();
}
public String getParameterNamedListAsString() {
if (_parameterNamedListAsString == null) {
StringBuffer returned = new StringBuffer();
boolean isFirst = true;
for (Enumeration en = _parameters.elements(); en.hasMoreElements();) {
DMMethodParameter next = (DMMethodParameter) en.nextElement();
String paramName = next.getName();
String typeName = "";
if (next.getType() != null) {
typeName = next.getType().getSimplifiedStringRepresentation();
}
returned.append((isFirst ? "" : ",") + typeName + " " + paramName);
isFirst = false;
}
_parameterNamedListAsString = returned.toString();
}
return _parameterNamedListAsString;
}
String getMethodHeader() {
StringBuffer methodHeader = new StringBuffer();
methodHeader.append(getModifiersAsString());
methodHeader.append(getReturnType() != null ? getReturnType().getSimplifiedStringRepresentation() : "void");
methodHeader.append(" ");
methodHeader.append(name);
methodHeader.append("(");
methodHeader.append(getParameterNamedListAsString());
methodHeader.append(")");
return methodHeader.toString();
}
private String _registeredWithSignature = null;
protected void _setRegisteredWithSignature(String aSignature) {
_registeredWithSignature = aSignature;
// _isRegistered = true;
}
protected String _getRegisteredWithSignature() {
return _registeredWithSignature;
}
protected void updateSignature() throws DuplicateMethodSignatureException {
_signatureFQ = null;
_signatureNFQ = null;
_parameterListAsStringFQ = null;
_parameterListAsString = null;
_parameterNamedListAsString = null;
if (!_isRegistered) {
return;
}
String oldSignature = _registeredWithSignature;
if (logger.isLoggable(Level.FINE)) {
logger.fine("Old signature was: " + oldSignature);
}
if (getEntity() != null && !getSignature().equals(oldSignature)) {
if (getEntity().getDeclaredMethod(getSignature()) != null) {
// TODO: s'occuper de ce probleme un jour
throw new DuplicateMethodSignatureException(getSignature());
} else {
if (logger.isLoggable(Level.FINE)) {
logger.fine("New signature is: " + getSignature());
}
if (oldSignature != null) {
getEntity().removeMethodWithKey(oldSignature);
}
getEntity().setMethodForKey(this, getSignature());
}
}
}
protected boolean _isRegistered = false;
protected void updateCode() {
if (isDeserializing()) {
return;
}
String oldCode = getSourceCode().getCode();
if (getSourceCode().isEdited()) {
getSourceCode().replaceMethodDeclarationInEditedCode(getMethodHeader());
ParsedJavadoc jd;
try {
jd = getSourceCode().parseJavadoc(oldCode);
if (jd != null) {
jd.setComment(getDescription());
Map<String, String> specificDescriptions = getSpecificDescriptions();
if (specificDescriptions != null && specificDescriptions.size() > 0) {
for (String key : specificDescriptions.keySet()) {
String specificDescription = ToolBox.getJavaDocString(specificDescriptions.get(key));
ParsedJavadocItem jdi = jd.getTagByName("doc", key);
if (jdi != null) {
jdi.setParameterValue(specificDescription);
} else {
jd.addTagForNameAndValue("doc", key, specificDescription, true);
}
}
}
if (getParameters().size() > 0) {
for (DMMethodParameter param : getParameters()) {
ParsedJavadocItem jdi = jd.getTagByName("param", param.getName());
if (jdi != null) {
jdi.setParameterValue(ToolBox.getJavaDocString(param.getDescription()));
} else {
jd.addTagForNameAndValue("param", param.getName(), ToolBox.getJavaDocString(param.getDescription()), false);
}
}
}
if (!isVoid()) {
ParsedJavadocItem jdi = jd.getTagByName("return");
if (jdi != null) {
jdi.setParameterValue(getReturnType().getStringRepresentation());
} else {
jd.addTagForNameAndValue("return", getReturnType().getSimplifiedStringRepresentation(), "", true);
}
}
// logger.info("Replacing javadoc with: "+jd.getStringRepresentation());
getSourceCode().replaceJavadocInEditedCode(jd);
}
else {
getSourceCode().replaceJavadocInEditedCode(getJavadoc() + StringUtils.LINE_SEPARATOR);
}
} catch (ParserNotInstalledException e) {
logger.warning("JavaParser not installed");
}
} else {
getSourceCode().updateComputedCode();
}
setChanged();
notifyObservers(new DMAttributeDataModification("code", oldCode, getCode()));
}
/*
* public String getCode() { return _code; }
*
* public void setCode(String code) { if (code.indexOf("{") != 0) code = "{"+StringUtils.LINE_SEPARATOR+code; if (!code.endsWith("}"))
* code = code+StringUtils.LINE_SEPARATOR+"}"; _code = code; try { updateSignature(); } catch (DuplicateMethodSignatureException e) { //
* Warns about the exception logger.warning ("Exception raised: "+e.getClass().getName()+". See console for details.");
* e.printStackTrace(); } setChanged(); }
*/
String getDefaultCoreCode() {
if (getEntity() instanceof LoadableDMEntity) {
return COMPILED_CODE;
}
if (getReturnType() == null || getReturnType().isVoid()) {
return VOID_DEFAULT_CODE;
} else if (getReturnType().isBoolean()) {
return BOOLEAN_DEFAULT_CODE;
} else if (getReturnType().isInteger()) {
return INT_DEFAULT_CODE;
} else if (getReturnType().isLong()) {
return BOOLEAN_DEFAULT_CODE;
} else if (getReturnType().isChar()) {
return CHAR_DEFAULT_CODE;
} else if (getReturnType().isFloat()) {
return FLOAT_DEFAULT_CODE;
} else if (getReturnType().isDouble()) {
return DOUBLE_DEFAULT_CODE;
} else {
return DEFAULT_CODE;
}
}
String getJavadoc() {
StringBuffer javadoc = new StringBuffer();
javadoc.append("/**" + StringUtils.LINE_SEPARATOR);
if (getEntity() instanceof LoadableDMEntity && (getDescription() == null || getDescription().equals(""))) {
javadoc.append(" * " + COMPILED_CODE_IN_JAVADOC + StringUtils.LINE_SEPARATOR);
} else if (getDescription() != null && getDescription().trim().length() > 0) {
javadoc.append(" * " + ToolBox.getJavaDocString(getDescription(), " "));
}
/*
* else if (getDescription() != null) { BufferedReader rdr = new BufferedReader(new StringReader(getDescription())); boolean
* hasMoreLines = true; while (hasMoreLines) { String currentLine = null; try { currentLine = rdr.readLine(); } catch (IOException
* e) {} if (currentLine != null) { currentLine = ToolBox.getJavaDocString(currentLine);
* javadoc.append(" * "+currentLine+StringUtils.LINE_SEPARATOR); } hasMoreLines = (currentLine != null); } }
*/
javadoc.append(" *" + StringUtils.LINE_SEPARATOR);
Map<String, String> specificDescriptions = getSpecificDescriptions();
if (specificDescriptions != null && specificDescriptions.size() > 0) {
for (String key : specificDescriptions.keySet()) {
String specificDescription = ToolBox.getJavaDocString(specificDescriptions.get(key));
// javadoc.append(" * @doc "+key+" "+specificDescription+StringUtils.LINE_SEPARATOR);
javadoc.append(getTagAndParamRepresentation("doc", key, specificDescription));
}
javadoc.append(" *" + StringUtils.LINE_SEPARATOR);
}
if (getParameters().size() > 0) {
for (DMMethodParameter param : getParameters()) {
javadoc.append(getTagAndParamRepresentation("param", param.getName(), ToolBox.getJavaDocString(param.getDescription())));
// javadoc.append(" * @param "+param.getName()+" "+param.getDescription()+StringUtils.LINE_SEPARATOR);
}
}
if (!isVoid()) {
javadoc.append(" * @return " + getReturnType().getSimplifiedStringRepresentation() + StringUtils.LINE_SEPARATOR);
}
javadoc.append(" */");
return javadoc.toString();
}
private MethodSourceCode sourceCode;
@Override
public void resetSourceCode() throws ParserNotInstalledException, DuplicateMethodSignatureException {
if (sourceCode != null) {
sourceCode.setCode("");
}
}
public MethodSourceCode getSourceCode() {
if (sourceCode == null) {
sourceCode = new MethodSourceCode(this/* ,"code","hasParseError","parseErrorWarning" */) {
@Override
public String makeComputedCode() {
return getJavadoc() + StringUtils.LINE_SEPARATOR + getMethodHeader() + " {" + StringUtils.LINE_SEPARATOR
+ getDefaultCoreCode() + StringUtils.LINE_SEPARATOR + "}";
}
@Override
public void interpretEditedJavaMethod(ParsedJavaMethod javaMethod) throws DuplicateMethodSignatureException {
logger.info(">>>>>>>>>>>> Interpret " + javaMethod);
try {
getJavaMethodParser().updateWith(DMMethod.this, javaMethod);
if (!isResolvable()) {
setHasParseErrors(true);
setParseErrorWarning("<html><font color=\"red\">" + FlexoLocalization.localizedForKey("unresolved_type(s)")
+ " : " + getUnresolvedTypes() + "</font></html>");
}
DMMethod.this.setChanged();
DMMethod.this
.notifyObserversAsReentrantModification(new DMAttributeDataModification("code", null, super.getCode()));
} catch (DuplicateMethodSignatureException e) {
setHasParseErrors(true);
setParseErrorWarning("<html><font color=\"red\">"
+ FlexoLocalization.localizedForKey("duplicated_method_signature") + "</font></html>");
throw e;
}
}
};
}
return sourceCode;
}
public boolean hasParseErrors() {
return getSourceCode().hasParseErrors();
}
public String getParseErrorWarning() {
return getSourceCode().getParseErrorWarning();
}
/**
* @deprecated
* @return
*/
@Deprecated
public String getCoreCode() {
if (isSerializing()) {
return null;
}
return getSourceCode().getCoreCode();
}
/**
* @deprecated
* @param someCode
*/
@Deprecated
public void setCoreCode(String someCoreCode) {
getSourceCode().updateComputedCode(
getJavadoc() + StringUtils.LINE_SEPARATOR + getMethodHeader() + " { " + StringUtils.LINE_SEPARATOR + someCoreCode
+ StringUtils.LINE_SEPARATOR + "}");
}
public String getCode() {
return getSourceCode().getCode();
}
public void setCode(String someCode) throws ParserNotInstalledException, DuplicateMethodSignatureException {
getSourceCode().setCode(someCode);
setChanged();
notifyObservers(new DMAttributeDataModification("code", null, someCode));
}
public String getModifiersAsString() {
return (getVisibilityModifier() != null ? getVisibilityModifier() != DMVisibilityType.NONE ? getVisibilityModifier().getName()
+ " " : "" : "")
+ (getIsStatic() ? "static" + " " : "")
+ (getIsAbstract() ? "abstract" + " " : "")
+ (getIsSynchronized() ? "synchronized" + " " : "");
}
public DMVisibilityType getVisibilityModifier() {
return _visibilityModifier;
}
public void setVisibilityModifier(DMVisibilityType visibilityModifier) {
if (visibilityModifier != _visibilityModifier) {
_visibilityModifier = visibilityModifier;
try {
updateSignature();
} catch (DuplicateMethodSignatureException e) {
// Warns about the exception
logger.warning("Exception raised: " + e.getClass().getName() + ". See console for details.");
e.printStackTrace();
}
setChanged();
notifyObservers(new DMAttributeDataModification("visibilityModifier", !isAbstract, isAbstract));
updateCode();
}
}
public boolean getIsAbstract() {
return isAbstract;
}
public void setIsAbstract(boolean isAbstract) {
if (isAbstract != this.isAbstract) {
this.isAbstract = isAbstract;
try {
updateSignature();
} catch (DuplicateMethodSignatureException e) {
// Warns about the exception
logger.warning("Exception raised: " + e.getClass().getName() + ". See console for details.");
e.printStackTrace();
}
setChanged();
notifyObservers(new DMAttributeDataModification("isAbstract", !isAbstract, isAbstract));
updateCode();
}
}
public boolean getIsStatic() {
return isStatic;
}
public void setIsStatic(boolean isStatic) {
if (isStatic != this.isStatic) {
this.isStatic = isStatic;
try {
updateSignature();
} catch (DuplicateMethodSignatureException e) {
// Warns about the exception
logger.warning("Exception raised: " + e.getClass().getName() + ". See console for details.");
e.printStackTrace();
}
setChanged();
notifyObservers(new DMAttributeDataModification("isStatic", !isStatic, isStatic));
updateCode();
}
}
public boolean getIsSynchronized() {
return isSynchronized;
}
public void setIsSynchronized(boolean isSynchronized) {
if (isSynchronized != this.isSynchronized) {
this.isSynchronized = isSynchronized;
try {
updateSignature();
} catch (DuplicateMethodSignatureException e) {
// Warns about the exception
logger.warning("Exception raised: " + e.getClass().getName() + ". See console for details.");
e.printStackTrace();
}
setChanged();
notifyObservers(new DMAttributeDataModification("isSynchronized", !isSynchronized, isSynchronized));
updateCode();
}
}
public Vector<DMMethodParameter> getParameters() {
return _parameters;
}
public void setParameters(Vector<DMMethodParameter> someParameters) throws DuplicateMethodSignatureException {
_parameters = someParameters;
updateSignature();
setChanged();
updateCode();
}
public void addToParameters(DMMethodParameter param) throws DuplicateMethodSignatureException {
param.setMethod(this);
_parameters.add(param);
updateSignature();
setChanged();
updateCode();
}
public void addToParametersNoCheck(DMMethodParameter param) {
param.setMethod(this);
_parameters.add(param);
_signatureFQ = null;
_signatureNFQ = null;
_parameterListAsStringFQ = null;
_parameterListAsString = null;
_parameterNamedListAsString = null;
setChanged();
}
public void removeFromParameters(DMMethodParameter param) throws DuplicateMethodSignatureException {
param.setMethod(null);
_parameters.remove(param);
updateSignature();
updateCode();
setChanged();
}
public void removeFromParametersNoCheck(DMMethodParameter param) {
param.setMethod(null);
_parameters.remove(param);
_signatureFQ = null;
_signatureNFQ = null;
_parameterListAsStringFQ = null;
_parameterListAsString = null;
_parameterNamedListAsString = null;
setChanged();
}
public DMMethodParameter getDMParameter(String aParamName) {
for (Enumeration en = _parameters.elements(); en.hasMoreElements();) {
DMMethodParameter next = (DMMethodParameter) en.nextElement();
if (next.getName().equals(aParamName)) {
return next;
}
}
return null;
}
/**
* @return
*/
public String getNextDefautParameterName() {
String baseName = FlexoLocalization.localizedForKey("default_new_parameter_name");
return getNextDefautParameterName(baseName);
}
/**
* @return
*/
public String getNextDefautParameterName(String baseName) {
String testMe = baseName;
int test = 0;
while (getDMParameter(testMe) != null) {
test++;
testMe = baseName + test;
}
return testMe;
}
public DMMethodParameter createNewParameter() throws DuplicateMethodSignatureException {
DMMethodParameter newParam = new DMMethodParameter(getDMModel(), this);
newParam.setName(getNextDefautParameterName());
addToParameters(newParam);
return newParam;
}
public void deleteParameter(DMMethodParameter param) throws DuplicateMethodSignatureException {
removeFromParameters(param);
}
public boolean isParameterDeletable(DMMethodParameter param) {
return true;
}
/**
* Return String uniquely identifying inspector template which must be applied when trying to inspect this object
*
* @return a String value
*/
@Override
public String getInspectorName() {
if (getIsReadOnly()) {
return Inspectors.DM.DM_RO_METHOD_INSPECTOR;
}
if (getDMRepository() == null || getDMRepository().isReadOnly()) {
return Inspectors.DM.DM_RO_METHOD_INSPECTOR;
} else {
return Inspectors.DM.DM_METHOD_INSPECTOR;
}
}
/**
* Return a Vector of embedded DMObjects at this level.
*
* @return null
*/
@Override
public Vector<DMObject> getEmbeddedDMObjects() {
return EMPTY_VECTOR;
}
public DMRepository getDMRepository() {
if (getEntity() != null) {
return getEntity().getRepository();
}
return null;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String newName) throws DuplicateMethodSignatureException {
if (name == null || !name.equals(newName)) {
DMEntity containerEntity = getEntity();
/*
* if (containerEntity != null) { containerEntity.unregisterMethod(this, false); }
*/
String oldName = name;
name = newName;
/*
* if (containerEntity != null) { containerEntity.registerMethod(this, false); }
*/
_signatureFQ = null;
_signatureNFQ = null;
if (logger.isLoggable(Level.FINE)) {
logger.fine("Change from " + oldName + " to " + newName + " new signature is " + getSignature());
}
if (!isDeserializing() && getEntity() != null && getEntity().getDeclaredMethod(getSignature()) != null) {
name = oldName;
throw new DuplicateMethodSignatureException(getSignature());
}
try {
updateSignature();
setChanged();
notifyObservers(new DMMethodNameChanged(this, oldName, newName));
if (containerEntity != null) {
containerEntity.notifyReordering(this);
}
} catch (DuplicateMethodSignatureException e) {
// Warns about the exception
logger.warning("Exception raised: " + e.getClass().getName() + ". See console for details.");
e.printStackTrace();
}
updateCode();
}
}
@Override
public DMEntity getEntity() {
return entity;
}
public void setEntity(DMEntity entity) {
this.entity = entity;
setChanged();
}
public boolean getIsReadOnly() {
if (getIsStaticallyDefinedInTemplate()) {
return true;
}
if (getEntity() != null) {
return getEntity().getIsReadOnly();
}
return false;
}
@Override
public DMType getType() {
return getReturnType();
}
@Override
public void setType(DMType type) {
setReturnType(type, true);
}
// private String returnTypeAsString;
public DMType getReturnType() {
/*
* if (_returnType==null && returnTypeAsString!=null) {
* setReturnType(getDMModel().getDmTypeConverter().convertFromString(returnTypeAsString), false); returnTypeAsString = null; }
*/
return _returnType;
}
public void setReturnType(DMType type) {
setReturnType(type, true);
}
public void setReturnType(DMType type, boolean notify) {
if (type == null && _returnType != null || type != null && !type.equals(_returnType)) {
DMType oldType = _returnType;
if (oldType != null) {
oldType.removeFromTypedWithThisType(this);
}
_returnType = type;
if (_returnType != null) {
_returnType.setOwner(this);
}
if (type != null) {
type.addToTypedWithThisType(this);
}
getSourceCode().updateComputedCode();
try {
updateSignature();
} catch (DuplicateMethodSignatureException e) {
// Warns about the exception
logger.warning("Exception raised: " + e.getClass().getName() + ". See console for details.");
e.printStackTrace();
}
if (notify) {
setChanged();
notifyObservers(new DMAttributeDataModification("returnType", oldType, type));
updateCode();
}
}
}
/*
* public String getReturnTypeAsString() { if (getReturnType()!=null) return
* getDMModel().getDmTypeConverter().convertToString(getReturnType()); else return null; }
*
* public void setReturnTypeAsString(String returnType) { returnTypeAsString = returnType; }
*/
/**
* @deprecated Use getReturnType() instead, kept for backward compatibility in XML mappings
* @return DMEntity
*/
@Deprecated
public DMEntity getReturnTypeBaseEntity() {
if (getReturnType() != null) {
return getReturnType().getBaseEntity();
}
return null;
}
/**
* @deprecated Use setReturnType(DMType) instead, kept for backward compatibility in XML mappings
* @param anEntity
*/
@Deprecated
public void setReturnTypeBaseEntity(DMEntity anEntity) {
setReturnType(DMType.makeResolvedDMType(anEntity), true);
}
public boolean isVoid() {
return getReturnType() == null || getReturnType().isVoid();
}
public boolean overrides(DMMethod method) {
if (method == null || method.getEntity() == null || method.getSignature() == null) {
return false;
}
return method.getEntity().isAncestorOf(getEntity()) && method.getSignature().equals(getSignature());
}
public String getStringRepresentation() {
return getSignature();
}
// ==========================================================================
// ======================== TreeNode implementation =========================
// ==========================================================================
@Override
public synchronized Vector<DMObject> getOrderedChildren() {
return EMPTY_VECTOR;
}
@Override
public DMEntity getParent() {
return getEntity();
}
@Override
public Vector<DMTypeVariable> getTypeVariables() {
if (getEntity() != null) {
return getEntity().getTypeVariables();
}
return null;
}
// ==========================================================================
// ==================== DMMethodParameter implementation ====================
// ==========================================================================
public static class DMMethodParameter extends DMObject implements Typed, DMGenericDeclaration, DMTypeOwner {
private DMType _type;
private DMMethod _method;
private String _name;
/**
* Constructor used during deserialization
*/
public DMMethodParameter(FlexoDMBuilder builder) {
this(builder.dmModel);
initializeDeserialization(builder);
}
/**
* Default constructor
*/
public DMMethodParameter(DMModel dmModel) {
super(dmModel);
}
/**
* Constructor used for dynamic creation
*/
public DMMethodParameter(DMModel dmModel, DMMethod method) {
this(dmModel);
this._method = method;
}
@Override
public void setIsModified() {
if (ignoreNotifications()) {
return;
}
super.setIsModified();
if (getMethod() != null) {
getMethod().setIsModified();
}
}
public void update(DMMethodParameter methodParameter, boolean updateDescription) {
// Name is supposed to be the same, but check anyway
if (!getName().equals(methodParameter.getName())) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Update name");
}
_name = methodParameter.getName();
} else {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Name is up-to-date");
}
}
// Type
if (_type != methodParameter.getType()) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Update type");
}
_type = methodParameter.getType();
} else {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Type is up-to-date");
}
}
// Description
if (getDescription() == null && methodParameter.getDescription() != null || getDescription() != null
&& !getDescription().equals(methodParameter.getDescription())) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Update description");
}
setDescription(methodParameter.getDescription());
} else {
if (logger.isLoggable(Level.FINE)) {
logger.fine("Description is up-to-date");
}
}
}
@Override
public String getName() {
return _name;
}
@Override
public void setName(String name) {
if (name == null && _name != null || name != null && !name.equals(_name)) {
String oldName = _name;
_name = name;
if (_method != null) {
_method._parameterNamedListAsString = null;
_method.updateCode();
}
setChanged();
notifyObservers(new DMAttributeDataModification("name", oldName, name));
}
}
@Override
public void setDescription(String aDescription) {
super.setDescription(aDescription);
if (_method != null) {
_method.updateCode();
}
}
@Override
public Vector<DMTypeVariable> getTypeVariables() {
if (getMethod() != null) {
return getMethod().getTypeVariables();
}
return null;
}
@Override
public boolean isDeletable() {
return _method.isDeletable();
}
// private String typeAsString;
@Override
public DMType getType() {
/*
* if (_type==null && typeAsString!=null) { setType(getDMModel().getDmTypeConverter().convertFromString(typeAsString),false);
* typeAsString = null; }
*/
return _type;
}
@Override
public void setType(DMType type) {
setType(type, true);
}
public void setType(DMType type, boolean notify) {
if (type == null && _type != null || type != null && !type.equals(_type)) {
DMType oldType = _type;
if (oldType != null) {
oldType.removeFromTypedWithThisType(this);
}
_type = type;
if (_type != null) {
_type.setOwner(this);
_type.addToTypedWithThisType(this);
}
if (_method != null) {
try {
_method.updateSignature();
} catch (DuplicateMethodSignatureException e) {
logger.warning("Exception raised: " + e.getClass().getName() + ". See console for details.");
e.printStackTrace();
}
_method._parameterNamedListAsString = null;
_method.updateCode();
}
if (notify) {
setChanged();
notifyObservers(new DMAttributeDataModification("type", oldType, type));
}
}
}
/*
* public String getTypeAsString() { if (getType()!=null) return getDMModel().getDmTypeConverter().convertToString(getType()); else
* return null; }
*
* public void setTypeAsString(String typeAsString) { this.typeAsString = typeAsString; }
*/
/**
* @deprecated Use getType() instead, kept for backward compatibility in XML mappings
* @return DMEntity
*/
@Deprecated
public DMEntity getTypeBaseEntity() {
if (getType() != null) {
return getType().getBaseEntity();
}
return null;
}
/**
* @deprecated Use setType(DMType) instead, kept for backward compatibility in XML mappings
* @param anEntity
*/
@Deprecated
public void setTypeBaseEntity(DMEntity anEntity) {
setType(DMType.makeResolvedDMType(anEntity));
}
public DMMethod getMethod() {
return _method;
}
public void setMethod(DMMethod method) {
_method = method;
}
@Override
public String getFullyQualifiedName() {
if (getMethod() != null) {
return getMethod().getFullyQualifiedName() + "." + getName();
}
return "NULL." + getName();
}
@Override
public Vector<DMObject> getOrderedChildren() {
return EMPTY_VECTOR;
}
@Override
public DMMethod getParent() {
return getMethod();
}
/**
* Return null since parameter is never inspected by its own
*
* @return null
*/
@Override
public String getInspectorName() {
return null;
}
/**
* Return a Vector of embedded DMObjects at this level.
*
* @return null
*/
@Override
public Vector<DMObject> getEmbeddedDMObjects() {
return EMPTY_VECTOR;
}
/*
* private Class _unresolvedTypeClass;
*
* public void setUnresolvedTypeClass(Class aClass) { _unresolvedTypeClass = aClass; }
*
* public Class getUnresolvedTypeClass() { return _unresolvedTypeClass; }
*/
/**
* Overrides getClassNameKey
*
* @see org.openflexo.foundation.FlexoModelObject#getClassNameKey()
*/
@Override
public String getClassNameKey() {
return "dm_methode_parameter";
}
/*
* private DMType _unresolvedType;
*
* public DMType getUnresolvedType() { return _unresolvedType; }
*
* public void setUnresolvedType(DMType unresolvedType2) { _unresolvedType = unresolvedType2; }
*/
@Override
public void update(FlexoObservable observable, DataModification dataModification) {
if (dataModification instanceof DMEntityClassNameChanged && observable == getType().getBaseEntity()) {
// Handle class name changed
updateTypeClassNameChange((String) ((DMEntityClassNameChanged) dataModification).oldValue(),
(String) ((DMEntityClassNameChanged) dataModification).newValue());
} else if (dataModification instanceof EntityDeleted && observable == getType().getBaseEntity()) {
DMEntity parent = getType().getBaseEntity();
while (parent != null && parent.isDeleted()) {
parent = parent.getParentBaseEntity();
}
if (parent != null) {
setType(DMType.makeResolvedDMType(parent));
} else {
setType(DMType.makeResolvedDMType(Object.class, getProject()));
}
} else if (dataModification instanceof TypeResolved) {
setChanged();
if (logger.isLoggable(Level.FINE)) {
logger.fine("Type resolved in DMMethodParameter: " + ((TypeResolved) dataModification).getType());
}
try {
getMethod().updateSignature();
} catch (DuplicateMethodSignatureException e) {
logger.warning("Inconsistent data: duplicate method signature for " + getMethod().getSignature());
e.printStackTrace();
}
getMethod().updateCode();
} else {
super.update(observable, dataModification);
}
}
private void updateTypeClassNameChange(String oldClassName, String newClassName) {
try {
_method.updateSignature();
_method.updateCode();
if (_method.getSourceCode().getCode() != null) {
_method.getSourceCode().setCode(
ToolBox.replaceStringByStringInString(oldClassName, newClassName, _method.getSourceCode().getCode()));
}
} catch (Exception e) {
e.printStackTrace();
}
_method.setChanged(true);
}
}
public static String signatureForMethod(Method aMethod, boolean fullyQualified) {
StringBuffer returned = new StringBuffer();
returned.append(aMethod.getName());
returned.append("(");
boolean isFirst = true;
for (int i = 0; i < aMethod.getGenericParameterTypes().length; i++) {
returned.append(isFirst ? "" : ",");
isFirst = false;
String parameterAsString;
if (fullyQualified) {
if (aMethod.getGenericParameterTypes()[i] instanceof Class) {
parameterAsString = ((Class) aMethod.getGenericParameterTypes()[i]).getCanonicalName();
} else {
parameterAsString = aMethod.getGenericParameterTypes()[i].toString();
}
} else {
if (aMethod.getGenericParameterTypes()[i] instanceof Class) {
parameterAsString = ((Class) aMethod.getGenericParameterTypes()[i]).getSimpleName();
} else {
parameterAsString = aMethod.getGenericParameterTypes()[i].toString();
}
}
// returned.append((fullyQualified?aMethod.getGenericParameterTypes()[i]:classNameForClass(aMethod.getParameterTypes()[i])));
returned.append(parameterAsString);
}
returned.append(")");
return returned.toString();
}
/**
* Overrides getClassNameKey
*
* @see org.openflexo.foundation.FlexoModelObject#getClassNameKey()
*/
@Override
public String getClassNameKey() {
return "dm_method";
}
// private DMType _unresolvedReturnType;
/*
* public DMType getUnresolvedReturnType() { return _unresolvedReturnType; }
*
* public void setUnresolvedReturnType(DMType unloadedReturnType) { _unresolvedReturnType = unloadedReturnType; }
*
* public String getUnresolvedReturnTypeName() { if (_unresolvedReturnType != null) return _unresolvedReturnType.getValue(); return
* "???"; }
*/
// private Vector<DMType> _unresolvedTypes = new Vector<DMType>();
/*
* public boolean isResolvable() { return (_unresolvedTypes.size() == 0); }
*
* public void addToUnresolvedTypes(DMType type) { logger.info(">>>> addToUnresolvedTypes() "+type); _unresolvedTypes.add(type); }
*
* public Vector<DMType> getUnresolvedTypes() { return _unresolvedTypes; }
*/
public boolean isResolvable() {
if (getReturnType() == null) {
return false;
}
if (!getReturnType().isResolved()) {
return false;
}
for (DMMethodParameter param : _parameters) {
if (param.getType() == null) {
return false;
}
if (!param.getType().isResolved()) {
return false;
}
}
return true;
}
public Vector<DMType> getUnresolvedTypes() {
Vector<DMType> unresolvedTypes = new Vector<DMType>();
if (!getReturnType().isResolved()) {
unresolvedTypes.add(getReturnType());
}
for (DMMethodParameter param : _parameters) {
if (param.getType() != null && !param.getType().isResolved()) {
unresolvedTypes.add(param.getType());
}
}
return unresolvedTypes;
}
@Override
public void update(FlexoObservable observable, DataModification dataModification) {
if (dataModification instanceof DMEntityClassNameChanged && observable == getType().getBaseEntity()) {
// Handle class name changed
updateTypeClassNameChange((String) ((DMEntityClassNameChanged) dataModification).oldValue(),
(String) ((DMEntityClassNameChanged) dataModification).newValue());
} else if (dataModification instanceof EntityDeleted && observable == getType().getBaseEntity()) {
DMEntity parent = getType().getBaseEntity();
while (parent != null && parent.isDeleted()) {
parent = parent.getParentBaseEntity();
}
if (parent != null) {
setType(DMType.makeResolvedDMType(parent));
} else {
setType(DMType.makeResolvedDMType(Object.class, getProject()));
}
} else if (dataModification instanceof TypeResolved) {
setChanged();
// logger.info("Type resolved !!!!! "+((TypeResolved)dataModification).getType());
try {
updateSignature();
} catch (DuplicateMethodSignatureException e) {
logger.warning("Inconsistent data: duplicate method signature for " + getSignature());
e.printStackTrace();
}
updateCode();
} else {
super.update(observable, dataModification);
}
}
private void updateTypeClassNameChange(String oldClassName, String newClassName) {
if (getSourceCode().getCode() != null) {
try {
getSourceCode().setCode(ToolBox.replaceStringByStringInString(oldClassName, newClassName, getSourceCode().getCode()));
} catch (ParserNotInstalledException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (DuplicateMethodSignatureException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
setChanged(true);
}
public boolean getIsStaticallyDefinedInTemplate() {
return _isStaticallyDefinedInTemplate;
}
public void setIsStaticallyDefinedInTemplate(boolean isStaticallyDefinedInTemplate) {
if (_isStaticallyDefinedInTemplate != isStaticallyDefinedInTemplate) {
_isStaticallyDefinedInTemplate = isStaticallyDefinedInTemplate;
setChanged();
notifyObservers(new DMAttributeDataModification("isStaticallyDefinedInTemplate", !isStaticallyDefinedInTemplate,
isStaticallyDefinedInTemplate));
}
}
@Override
public boolean codeIsComputable() {
return true;
}
}