/* * 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"; } }