| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.apache.openjpa.meta; |
| |
| import org.apache.openjpa.lib.util.Localizer; |
| import org.apache.openjpa.util.UserException; |
| |
| /** |
| * Represents access styles for members of a class and field through a |
| * 5-bit integer. |
| * <br> |
| * |
| * The bits designate following aspects of access style being used at class |
| * level:<br> |
| * |
| * <LI>Bit position 0 (UNKNOWN): generally 0. All bits as zero represent |
| * that no access style has been set. 1 denotes that the |
| * class has no property at all and its access can not be |
| * determined. |
| * <LI>Bit position 1 (FIELD): Field based access is default |
| * <LI>Bit position 2 (PROPERTY): Property based access is default |
| * <LI>Bit position 3 (EXPLICIT): whether explicit or implicit |
| * Explicit access style allows members to use mixed access style, |
| * implicit access style does not |
| * <LI>Bit position 4 (MIXED): whether all members are using the same |
| * access style or not. Can only be set if EXPLICT bit is set. |
| * If set, then bit 1 or 2 denotes what is the default. |
| * <br> |
| * The same bits designate following aspects of access style being used at field |
| * level:<br> |
| * |
| * <LI>Bit position 0 (UNKNOWN): always 0. All bits as zero represent |
| * that no access style has been set. |
| * <LI>Bit position 1 (FIELD): Field based access is default |
| * <LI>Bit position 2 (PROPERTY): Property based access is default |
| * <LI>Bit position 3 (EXPLICIT): whether the access is explicit or implicit |
| * <LI>Bit position 4 (MIXED): not used |
| * <br> |
| * |
| * <p> |
| * Validation Rules for the bits:<br> |
| * <LI>1. Only one of the position 1 (FIELD) and 2 (PROPERTY) can |
| * be set. A single bit is not used for legacy reason to cope with the access |
| * constants used in ClassMetaData which this class now refactors to address |
| * new behaviors specified in JPA 2.0 specification. |
| * <LI>2. if position 3 (EXPLICIT) is set then one of position 1 |
| * (FIELD) and 2 (PROPERTY) must be set. |
| * <LI>3. If position 4 (MIXED) is set then the set position of either |
| * FIELD or PROPERTY designates the default access of the |
| * member. |
| * |
| * @author Pinaki Poddar |
| * |
| * @since 2.0.0 |
| */ |
| public class AccessCode { |
| public static int UNKNOWN = 0; |
| public static int EMPTY = 1; |
| public static int FIELD = 2 << 0; |
| public static int PROPERTY = 2 << 1; |
| public static int EXPLICIT = 2 << 2; |
| public static int MIXED = 2 << 3; |
| |
| private static Localizer _loc = Localizer.forPackage(AccessCode.class); |
| |
| /** |
| * Affirms if the given code is valid. |
| */ |
| public static boolean isValidClassCode(int code) { |
| if (code == EMPTY) |
| return true; |
| return (code%2 == 0 || code == EMPTY) |
| && code >= UNKNOWN |
| && code <= (MIXED|EXPLICIT|PROPERTY) |
| && !(isProperty(code) && isField(code)) // both 1 & 2 can not be set |
| && (isProperty(code) || isField(code) || isUnknown(code)) |
| && ((isMixed(code) && isExplicit(code)) || !isMixed(code)); |
| } |
| |
| public static boolean isValidFieldCode(int code) { |
| return code%2 == 0 // code must be even |
| && code >= UNKNOWN |
| && code <= (EXPLICIT|PROPERTY) |
| && !(isProperty(code) && isField(code)) |
| && (isProperty(code) || isField(code) || isUnknown(code)); |
| } |
| |
| /** |
| * Affirms if the given code designates that members can use both |
| * FIELD and PROPERTY based access. |
| */ |
| public static boolean isMixed(int code) { |
| return (code & MIXED) != 0; |
| } |
| |
| public static boolean isExplicit(int code) { |
| return (code & EXPLICIT) != 0; |
| } |
| |
| public static boolean isProperty(int code) { |
| return (code & PROPERTY) != 0; |
| } |
| |
| public static boolean isField(int code) { |
| return (code & FIELD) != 0; |
| } |
| |
| public static boolean isUnknown(int code) { |
| return code == UNKNOWN; |
| } |
| |
| public static boolean isEmpty(int code) { |
| return code == EMPTY; |
| } |
| |
| public static boolean isField(ClassMetaData meta) { |
| return isField(meta.getAccessType()); |
| } |
| |
| public static boolean isProperty(ClassMetaData meta) { |
| return isProperty(meta.getAccessType()); |
| } |
| |
| public static boolean isUnknown(ClassMetaData meta) { |
| return isUnknown(meta.getAccessType()); |
| } |
| |
| public static boolean isEmpty(ClassMetaData meta) { |
| return isEmpty(meta.getAccessType()); |
| } |
| |
| public static boolean isField(FieldMetaData meta) { |
| return isField(meta.getAccessType()); |
| } |
| |
| public static boolean isProperty(FieldMetaData meta) { |
| return isProperty(meta.getAccessType()); |
| } |
| |
| public static boolean isUnknown(FieldMetaData meta) { |
| return isUnknown(meta.getAccessType()); |
| } |
| |
| /** |
| * Affirms if the sub class access type is compatible with super class |
| * access style. |
| */ |
| public static boolean isCompatibleSuper(int subCode, int superCode) { |
| if (isEmpty(superCode)) |
| return true; |
| if (isValidClassCode(subCode) && isValidClassCode(superCode)) { |
| if (isExplicit(subCode)) |
| return true; |
| return subCode == superCode; |
| } |
| return false; |
| } |
| |
| public static int mergeFieldCode(ClassMetaData meta, FieldMetaData fmd, |
| int fCode) { |
| int cCode = meta.getAccessType(); |
| try { |
| return mergeFieldCode(cCode, fCode); |
| } catch (IllegalStateException e) { |
| throw new UserException(_loc.get("access-illegal-merge", |
| fmd.getFullName(false), toFieldString(fCode), |
| toClassString(cCode))); |
| } |
| } |
| |
| /** |
| * Merges the field access type with the class access type provided such |
| * merge is valid. |
| * |
| * @return the modified class access code. |
| * @exception IllegalStateException if the given codes are not compatible |
| */ |
| public static int mergeFieldCode(int cCode, int fCode) { |
| if (isValidClassCode(cCode) && isValidFieldCode(fCode)) { |
| if (isUnknown(cCode)) { |
| if (isUnknown(fCode)) |
| return UNKNOWN; |
| return isProperty(fCode) ? PROPERTY : FIELD; |
| } |
| boolean mixed = isProperty(cCode) != isProperty(fCode); |
| if (isExplicit(cCode)) { |
| if (mixed) { |
| return MIXED | cCode; |
| } else { |
| return cCode; |
| } |
| } else { // default, implicit access |
| if (fCode == cCode) |
| return cCode; |
| else |
| throw new IllegalStateException( |
| (_loc.get("access-cannot-merge", |
| toFieldString(fCode), |
| toClassString(cCode)).toString())); |
| } |
| } |
| return cCode; |
| } |
| |
| public static int getMixedCode(int cCode, int fCode) { |
| if (isMixed(cCode) || (isProperty(cCode) == isProperty(fCode))) |
| return cCode; |
| return MIXED | cCode; |
| } |
| |
| public static int toFieldCode(int code) { |
| if (isProperty(code)) |
| return PROPERTY; |
| if (isField(code)) |
| return FIELD; |
| return UNKNOWN; |
| } |
| |
| public static String toFieldString(int code) { |
| if (!isValidFieldCode(code)) |
| return "invalid code " + code; |
| if (code == UNKNOWN) |
| return "unknown access"; |
| if (code == EMPTY) |
| return "empty access"; |
| return (isMixed(code) ? "mixed " : "") |
| + (isExplicit(code) ? "explicit " : "implicit ") |
| + (isField(code) ? "field" : "property") |
| + " access"; |
| } |
| |
| public static String toClassString(int code) { |
| if (!isValidClassCode(code)) |
| return "invalid code " + code; |
| if (code == UNKNOWN) |
| return "unknown access"; |
| if (code == EMPTY) |
| return "empty access"; |
| return (isMixed(code) ? "mixed " : "") |
| + (isExplicit(code) ? "explicit " : "implicit ") |
| + (isField(code) ? "field" : "property") |
| + " access"; |
| } |
| } |