blob: 1fc7e291280ac156bdeb0cd9f7c1c1e754ad373c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jst.j2ee.internal.java.codegen;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.jdom.IDOMField;
import org.eclipse.jdt.core.jdom.IDOMMember;
import org.eclipse.jdt.core.jdom.IDOMMethod;
import org.eclipse.jdt.core.jdom.IDOMType;
/**
* This merge strategy abstract base class implements some of the {@link IJavaMergeStrategy}api and
* provides infrastructure for subclass concrete implementations.
*
* @see IJavaMergeStrategy
*/
public abstract class JavaMergeStrategy implements IJavaMergeStrategy {
private boolean fDefaultPreserveNonCollisionOldMembers = false;
private boolean fDefaultIncrementalPreserveCollision = false;
protected static final String DEFAULT_GENERATED_MEMBER_FLAG = "@generated";//$NON-NLS-1$
protected static final String DEFAULT_USER_CODE_BEGIN = "// user code begin";//$NON-NLS-1$
protected static final String DEFAULT_USER_CODE_BEGIN_TEMPLATE = DEFAULT_USER_CODE_BEGIN + " {%0}";//$NON-NLS-1$
protected static final String DEFAULT_USER_CODE_END = "// user code end";//$NON-NLS-1$
/**
* JavaMergeStrategy default constructor.
*/
public JavaMergeStrategy() {
super();
}
/**
* The default default field merglet is {@link JavaFieldMerglet}.
*
* @see IJavaMergeStrategy
*/
public IJavaMerglet createDefaultFieldMerglet() {
return new JavaFieldMerglet(this);
}
/**
* The default default method merglet is {@link JavaMethodMerglet}.
*
* @see IJavaMergeStrategy
*/
public IJavaMerglet createDefaultMethodMerglet() {
return new JavaMethodMerglet(this);
}
/**
* The default default type merglet is {@link JavaTypeMerglet}.
*
* @see IJavaMergeStrategy
*/
public IJavaMerglet createDefaultTypeMerglet() {
return new JavaTypeMerglet(this);
}
/**
* Creates the merge results object from the history object. Subclasses would want to override
* if they have a specialization of MergeResults and/or the history descriptor.
*/
protected MergeResults createInitialMergeResults(JavaMemberHistoryDescriptor histDesc) {
MergeResults mr = new MergeResults();
mr.setDeleteOnly(histDesc.isDeleteOnly());
mr.setOldMember(histDesc.getOldMember());
mr.setCollisionMember(histDesc.getCollisionMember());
return mr;
}
/**
* @see IJavaMergeStrategy
*/
public String getGeneratedMemberTag() {
return DEFAULT_GENERATED_MEMBER_FLAG;
}
/**
* @see IJavaMergeStrategy
*/
public String getUserCodeBegin() {
return DEFAULT_USER_CODE_BEGIN;
}
/**
* @see IJavaMergeStrategy
*/
public String getUserCodeBeginTemplate() {
return DEFAULT_USER_CODE_BEGIN_TEMPLATE;
}
/**
* @see IJavaMergeStrategy
*/
public String getUserCodeEnd() {
return DEFAULT_USER_CODE_END;
}
/**
* @see IJavaMergeStrategy
*/
public boolean isDefaultIncrementalPreserveCollision() {
return fDefaultIncrementalPreserveCollision;
}
/**
* @see IJavaMergeStrategy
*/
public boolean isDefaultPreserveNonCollisionOldMembers() {
return fDefaultPreserveNonCollisionOldMembers;
}
/**
* @see IJavaMergeStrategy
*/
public MergeResults merge(JavaMemberHistoryDescriptor histDesc, IDOMField newField) throws MergeException {
return merge(histDesc, newField, createDefaultFieldMerglet());
}
/**
* @see IJavaMergeStrategy
*/
public MergeResults merge(JavaMemberHistoryDescriptor histDesc, IDOMMember newMember, IJavaMerglet merglet) throws MergeException {
// Set up our results and get the old member for tests.
MergeResults mr = createInitialMergeResults(histDesc);
// If this is delete only, we only need to check the old member.
if (mr.isDeleteOnly())
mergeForDeleteOnly(mr, merglet);
else
mergeForGenerate(mr, newMember, merglet);
return mr;
}
/**
* @see IJavaMergeStrategy The default strategy only generates the type if it does not exist or
* the old member was marked generated. It doesn't generate if the old and new are exactly
* the same either.
*/
public MergeResults merge(JavaMemberHistoryDescriptor histDesc, IDOMType newType) throws MergeException {
return merge(histDesc, newType, createDefaultTypeMerglet());
}
/**
* @see IJavaMergeStrategy
*/
public MergeResults merge(JavaMethodHistoryDescriptor histDesc, IDOMMethod newMethod) throws MergeException {
return merge(histDesc, newMethod, createDefaultMethodMerglet());
}
/**
* {@link JavaMergeStrategy#merge(JavaMemberHistoryDescriptor, IDOMMember, IJavaMerglet)}uses
* this method for merging if the member history descriptor (see
* {@link JavaMemberHistoryDescriptor}) indicated that the only action expected is a delete of
* the old member.
* <p>
* This method uses {@link IJavaMerglet#validateForDeleteOnly(MergeResults)}to decide of the
* delete only generation is allowed. If the delete is disallowed,
* {@link MergeResults#isGenerate()}is set to false.
*
* @exception org.eclipse.jst.j2ee.internal.internal.internal.java.codegen.MergeException
*/
protected void mergeForDeleteOnly(MergeResults mr, IJavaMerglet merglet) throws MergeException {
if (mr.getOldMember() != null) {
mr.setGenerate(merglet.validateForDeleteOnly(mr));
} else {
// No need to delete a member that is not there.
mr.setGenerate(false);
}
}
/**
* {@link JavaMergeStrategy#merge(JavaMemberHistoryDescriptor, IDOMMember, IJavaMerglet)}uses
* this method for merging if the member history descriptor (see
* {@link JavaMemberHistoryDescriptor}) did <b>not </b> indicate that the only action expected
* is a delete of the old member.
* <p>
* Checks that we need to generate and that we can generate. Also sets up for needed deletions.
* Uses {@link IJavaMerglet#validateCollision(MergeResults)},
* {@link IJavaMerglet#isPreserveNonCollisionOldMembers()},
* {@link IJavaMerglet#validateForDelete(MergeResults)},
* {@link IJavaMerglet#isIncrementalPreserveCollision()}and
* {@link IJavaMerglet#merge(MergeResults, IDOMMember)}.
*
* @exception org.eclipse.jst.j2ee.internal.internal.internal.java.codegen.MergeException
*/
protected void mergeForGenerate(MergeResults mr, IDOMMember newMember, IJavaMerglet merglet) throws MergeException {
// Check for collisions that cause us not to want to generate the new member.
boolean needToGenerate = merglet.validateCollision(mr);
// If the old member is not null and is different
// than the collision member and the merglet does not
// necessarily want to preserve old non collision members,
// we need to make sure it is okay to delete it.
boolean okayToDeleteOldMember = false;
if ((mr.getOldMember() != null) && (mr.getOldMember() != mr.getCollisionMember()) && (!merglet.isPreserveNonCollisionOldMembers()))
okayToDeleteOldMember = merglet.validateForDelete(mr);
// If we collided above, we do not need to generate.
if (needToGenerate) {
// At this point we think we are generating a member, however
// the merglet could decide the generation is not needed because
// the result is the same as the collision member.
// Also need to consider incremental collision replacement.
if (!isBatchGeneration() && merglet.isIncrementalPreserveCollision() && (mr.getCollisionMember() != null))
needToGenerate = false;
else
needToGenerate = merglet.merge(mr, newMember);
}
// If the merglet decided to generate the new member...
if (needToGenerate) {
// We will generate the new member. If it is not
// okay to delete the old member, clear the old
// member out because we want to leave it.
if (!okayToDeleteOldMember)
mr.setOldMember(null);
} else {
// If there is an old member that is okay to delete, revert to delete only.
if (okayToDeleteOldMember)
mr.setDeleteOnly(true);
else
mr.setGenerate(false);
}
}
/**
* @see IJavaMergeStrategy
*/
public void setDefaultIncrementalPreserveCollision(boolean newDefaultIncrementalPreserveCollision) {
fDefaultIncrementalPreserveCollision = newDefaultIncrementalPreserveCollision;
}
/**
* @see IJavaMergeStrategy
*/
public void setDefaultPreserveNonCollisionOldMembers(boolean newDefaultPreserveNonCollisionOldMembers) {
fDefaultPreserveNonCollisionOldMembers = newDefaultPreserveNonCollisionOldMembers;
}
/**
* @see IJavaMergeStrategy
*/
public boolean wasGenerated(String source, int endCheckIndex) {
if (source == null)
return true;
boolean foundGeneratedFlag = false;
if (endCheckIndex <= 0)
foundGeneratedFlag = (source.indexOf(getGeneratedMemberTag()) >= 0);
else
foundGeneratedFlag = (source.lastIndexOf(getGeneratedMemberTag(), endCheckIndex) >= 0);
return foundGeneratedFlag;
}
/**
* @see IJavaMergeStrategy
*/
public boolean wasGenerated(IMember member) throws MergeException {
if ((member == null) || (!member.exists()))
return true;
boolean foundGeneratedFlag = false;
try {
int endCheckIndex = member.getNameRange().getOffset() - member.getSourceRange().getOffset();
foundGeneratedFlag = wasGenerated(member.getSource(), endCheckIndex);
} catch (JavaModelException exc) {
throw new MergeException(exc);
}
return foundGeneratedFlag;
}
}