/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.tools.workbench.mappingsmodel.meta; import java.io.PrintWriter; import java.lang.reflect.Modifier; import org.eclipse.persistence.tools.workbench.mappingsmodel.MWModel; import org.eclipse.persistence.tools.workbench.utility.node.Node; import org.eclipse.persistence.descriptors.ClassDescriptor; import org.eclipse.persistence.mappings.DirectToFieldMapping; import org.eclipse.persistence.internal.codegen.AccessLevel; /** * This class is heavier than java.lang.reflect.Modifier, * but it allows us to delegate a bit of behavior to it. */ public final class MWModifier extends MWModel { /** * the modifiers are bit flags in this int; * these are the same as the Java bit flags; * except that we don't keep the "interface" setting here * @see java.lang.reflect.Modifier */ private volatile int code; public static final String CODE_PROPERTY = "code"; /** access level "virtual" property */ public static final String ACCESS_LEVEL_PROPERTY = "accessLevel"; public static final String PUBLIC = "public"; public static final String PACKAGE = "package"; public static final String PROTECTED = "protected"; public static final String PRIVATE = "private"; // ********** constructors ********** /** * Default constructor - for TopLink use only. */ private MWModifier() { super(); } /** * construct the default modifier, * which is simply "public" */ MWModifier(MWModifiable parent) { super((MWModel) parent); } /** * to set up more than one modifier, "OR" (|) them together; e.g. * public static => Modifier.PUBLIC | Modifier.STATIC * @see java.lang.reflect.Modifier */ MWModifier(MWModifiable parent, int code) { this(parent); this.setCode(code); } // ********** initialization ********** /** * initialize persistent state */ protected void initialize(Node parent) { // private-protected super.initialize(parent); this.code = defaultCode(); } /** * this is used when renaming a type */ void initializeFrom(MWModifier oldModifier) { this.setCode(oldModifier.getCode()); } /** * re-initialize the modifer to its default settings */ void clear() { this.setCode(defaultCode()); } // ********** accessors ********** /** * @see java.lang.reflect.Modifier */ public int getCode() { return this.code; } /** * @see java.lang.reflect.Modifier */ public void setCode(int code) { int old = this.code; this.setCodeInternal(code); this.firePropertyChanged(CODE_PROPERTY, old, this.code); if (old != this.code) { this.modifiableParent().modifierChanged(old, this.code); } } private void setCodeInternal(int code) { // always clear the interface bit - it is maintained in MWClass code &= ~Modifier.INTERFACE; this.code = code; } /** * allow the code to be set unchecked */ void setCodeForTopLink(int code) { this.setCodeInternal(code); } private void setBit(boolean value, int mask) { int temp = this.code; if (value) { temp |= mask; } else { temp &= ~mask; } this.setCode(temp); } /** * abstract */ public boolean supportsAbstract() { return this.modifiableParent().supportsAbstract(); } public boolean canBeSetAbstract() { return this.modifiableParent().canBeSetAbstract(); } public boolean isAbstract() { return Modifier.isAbstract(this.code); } public void setAbstract(boolean value) { this.setBit(value, Modifier.ABSTRACT); } /** * final */ public boolean canBeSetFinal() { return this.modifiableParent().canBeSetFinal(); } public boolean isFinal() { return Modifier.isFinal(this.code); } public void setFinal(boolean value) { this.setBit(value, Modifier.FINAL); } /** * interface * we keep this setting in MWClass... */ private boolean supportsInterface() { return this.modifiableParent().supportsInterface(); } private boolean canBeSetInterface() { return this.modifiableParent().canBeSetInterface(); } private boolean isInterface() { return Modifier.isInterface(this.code); } private void setInterface(boolean value) { this.setBit(value, Modifier.INTERFACE); } /** * native */ public boolean supportsNative() { return this.modifiableParent().supportsNative(); } public boolean canBeSetNative() { return this.modifiableParent().canBeSetNative(); } public boolean isNative() { return Modifier.isNative(this.code); } public void setNative(boolean value) { this.setBit(value, Modifier.NATIVE); } /** * access level (virtual) */ public String getAccessLevel() { if (this.isPublic()) { return PUBLIC; } else if (this.isProtected()) { return PROTECTED; } else if (this.isPackage()) { return PACKAGE; } else if (this.isPrivate()) { return PRIVATE; } else { throw new IllegalStateException(this.toString()); } } public void setAccessLevel(String accessLevel) { String old = this.getAccessLevel(); if (accessLevel == PUBLIC) { this.setPublic(true); } else if (accessLevel == PROTECTED) { this.setProtected(true); } else if (accessLevel == PRIVATE) { this.setPrivate(true); } else if (accessLevel == PACKAGE) { this.setPackage(true); } else { throw new IllegalArgumentException("Allowable values: MWModifier.PUBLIC, MWModifier.PROTECTED, MWModifier.PRIVATE, MWModifier.PACKAGE"); } this.firePropertyChanged(ACCESS_LEVEL_PROPERTY, old, accessLevel); if (this.attributeValueHasChanged(old, accessLevel)) { this.modifiableParent().accessLevelChanged(old, accessLevel); } } /** * package * there is no mask for package/default access; * it is implied by the absence of all the other access modifiers */ public boolean canBeSetPackage() { return this.modifiableParent().canBeSetPackage(); } public boolean isPackage() { return ! this.isPublic() && ! this.isPrivate() && ! this.isProtected(); } public void setPackage(boolean value) { int temp = this.code; if (value) { temp &= ~Modifier.PUBLIC; } else { // if false, then the access modifier is set to public by default temp |= Modifier.PUBLIC; } temp &= ~Modifier.PRIVATE; temp &= ~Modifier.PROTECTED; this.setCode(temp); } /** * private */ public boolean canBeSetPrivate() { return this.modifiableParent().canBeSetPrivate(); } public boolean isPrivate() { return Modifier.isPrivate(this.code); } public void setPrivate(boolean value) { int temp = this.code; if (value) { temp |= Modifier.PRIVATE; temp &= ~Modifier.PROTECTED; temp &= ~Modifier.PUBLIC; } else { temp &= ~Modifier.PRIVATE; } this.setCode(temp); } /** * protected */ public boolean canBeSetProtected() { return this.modifiableParent().canBeSetProtected(); } public boolean isProtected() { return Modifier.isProtected(this.code); } public void setProtected(boolean value) { int temp = this.code; if (value) { temp |= Modifier.PROTECTED; temp &= ~Modifier.PRIVATE; temp &= ~Modifier.PUBLIC; } else { temp &= ~Modifier.PROTECTED; } this.setCode(temp); } /** * public */ public boolean canBeSetPublic() { return this.modifiableParent().canBeSetPublic(); } public boolean isPublic() { return Modifier.isPublic(this.code); } public void setPublic(boolean value) { int temp = this.code; if (value) { temp |= Modifier.PUBLIC; temp &= ~Modifier.PRIVATE; temp &= ~Modifier.PROTECTED; } else { temp &= ~Modifier.PUBLIC; } this.setCode(temp); } /** * static */ public boolean canBeSetStatic() { return this.modifiableParent().canBeSetStatic(); } public boolean isStatic() { return Modifier.isStatic(this.code); } public void setStatic(boolean value) { this.setBit(value, Modifier.STATIC); } /** * strict */ public boolean supportsStrict() { return this.modifiableParent().supportsStrict(); } public boolean canBeSetStrict() { return this.modifiableParent().canBeSetStrict(); } public boolean isStrict() { return Modifier.isStrict(this.code); } public void setStrict(boolean value) { this.setBit(value, Modifier.STRICT); } /** * synchronized */ public boolean supportsSynchronized() { return this.modifiableParent().supportsSynchronized(); } public boolean canBeSetSynchronized() { return this.modifiableParent().canBeSetSynchronized(); } public boolean isSynchronized() { return Modifier.isSynchronized(this.code); } public void setSynchronized(boolean value) { this.setBit(value, Modifier.SYNCHRONIZED); } /** * transient */ public boolean supportsTransient() { return this.modifiableParent().supportsTransient(); } public boolean canBeSetTransient() { return this.modifiableParent().canBeSetTransient(); } public boolean isTransient() { return Modifier.isTransient(this.code); } public void setTransient(boolean value) { this.setBit(value, Modifier.TRANSIENT); } /** * volatile */ public boolean supportsVolatile() { return this.modifiableParent().supportsVolatile(); } public boolean canBeSetVolatile() { return this.modifiableParent().canBeSetVolatile(); } public boolean isVolatile() { return Modifier.isVolatile(this.code); } public void setVolatile(boolean value) { this.setBit(value, Modifier.VOLATILE); } // ********** queries ********** /** * convenience method - cast the parent */ private MWModifiable modifiableParent() { return (MWModifiable) this.getMWParent(); } public static int defaultCode() { return Modifier.PUBLIC; } public boolean isDefaultValue() { return this.code == defaultCode(); } /** * used by Wallace code gen */ AccessLevel accessLevel() { AccessLevel accessLevel = new AccessLevel(); if (this.isPublic()) { accessLevel.setLevel(AccessLevel.PUBLIC); } else if (this.isProtected()) { accessLevel.setLevel(AccessLevel.PROTECTED); } else if (this.isPackage()) { accessLevel.setLevel(AccessLevel.PACKAGE); } else { accessLevel.setLevel(AccessLevel.PRIVATE); } accessLevel.setIsAbstract(this.isAbstract()); accessLevel.setIsFinal(this.isFinal()); accessLevel.setIsNative(this.isNative()); accessLevel.setIsStatic(this.isStatic()); accessLevel.setIsSynchronized(this.isSynchronized()); accessLevel.setIsTransient(this.isTransient()); accessLevel.setIsVolatile(this.isVolatile()); return accessLevel; } // ********** behavior ********** void refresh(int javaModifiers) { this.setCode(javaModifiers); } /** * notify listeners of a change to the * modifier's "allowable" settings; i.e. this notification * will be sent out when the modifier's response to the * #canBeSet___() methods has changed. */ void allowedModifiersChanged() { this.fireStateChanged(); } /** * currently unused... * check the code for validity; these checks only apply * to source code declarations, not declarations that are * compiler-generated (e.g. anonymous inner classes) */ private void checkCode() { if ((this.isPublic() && ! this.canBeSetPublic()) || (this.isProtected() && ! this.canBeSetProtected()) || (this.isPackage() && ! this.canBeSetPackage()) || (this.isPrivate() && ! this.canBeSetPrivate()) || (this.isInterface() && ! this.canBeSetInterface()) || (this.isFinal() && ! this.canBeSetFinal()) || (this.isStatic() && ! this.canBeSetStatic()) || (this.isAbstract() && ! this.canBeSetAbstract()) || (this.isNative() && ! this.canBeSetNative()) || (this.isStrict() && ! this.canBeSetStrict()) || (this.isSynchronized() && ! this.canBeSetSynchronized()) || (this.isTransient() && ! this.canBeSetTransient()) || (this.isVolatile() && ! this.canBeSetVolatile())) { throw new IllegalStateException(this.toString()); } } // ********** displaying and printing ********** public String displayString() { return Modifier.toString(this.code); } public void toString(StringBuffer sb) { sb.append(this.displayString()); } /** * append the modifier's source representation to the writer; * return true if any source was actually written to the writer * (it is possible that no source was written out); * this return value allows callers to know whether to append * a space if necessary */ boolean writeSource(PrintWriter pw) { String source = Modifier.toString(this.code); if (source.length() == 0) { return false; } pw.print(source); return true; } // ********** static methods ********** /** * Return whether *all* of the specified flags in the specified * codes are the same. * @see java.lang.reflect.Modifier */ static boolean flagsAreSame(int flags, int code1, int code2) { return (code1 & flags) == (code2 & flags); } /** * Return whether *any* of the specified flags in the specified * codes are different. * @see java.lang.reflect.Modifier */ static boolean anyFlagsAreDifferent(int flags, int code1, int code2) { return ! flagsAreSame(flags, code1, code2); } }