001: /**********************************************************************
002: Copyright (c) 2006 Andy Jefferson and others. All rights reserved.
003: Licensed under the Apache License, Version 2.0 (the "License");
004: you may not use this file except in compliance with the License.
005: You may obtain a copy of the License at
006:
007: http://www.apache.org/licenses/LICENSE-2.0
008:
009: Unless required by applicable law or agreed to in writing, software
010: distributed under the License is distributed on an "AS IS" BASIS,
011: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: See the License for the specific language governing permissions and
013: limitations under the License.
014:
015: Contributors:
016: ...
017: **********************************************************************/package org.jpox.store;
018:
019: import org.jpox.exceptions.JPOXUserException;
020: import org.jpox.store.IdentifierFactory;
021: import org.jpox.util.JPOXLogger;
022: import org.jpox.util.Localiser;
023:
024: /**
025: * Abstract representation of an identifier factory.
026: * To be extended to generate the identifiers.
027: *
028: * @version $Revision: 1.9 $
029: */
030: public abstract class AbstractIdentifierFactory implements
031: IdentifierFactory {
032: /** Localiser for messages. */
033: protected static final Localiser LOCALISER = Localiser
034: .getInstance("org.jpox.store.Localisation");
035:
036: public static final int CASE_PRESERVE = 1;
037: public static final int CASE_UPPER = 2;
038: public static final int CASE_LOWER = 3;
039:
040: /** Adapter for the datastore. */
041: protected DatastoreAdapter dba;
042:
043: /** Case to use for identifiers. */
044: protected int identifierCase;
045:
046: /** Range to use for creating hased ending when truncating identifiers. */
047: private static final int HASH_RANGE = Character.MAX_RADIX
048: * Character.MAX_RADIX / 2;
049:
050: /**
051: * Constructor.
052: * @param dba Datastore adapter
053: * @param requiredCase The case the user requires
054: * @throws JPOXUserException if invalid input is encountered
055: */
056: public AbstractIdentifierFactory(DatastoreAdapter dba,
057: String requiredCase) {
058: this .dba = dba;
059:
060: // Set the identifier case to be used based on what the user has requested and what the datastore supports
061: int userIdentifierCase = CASE_UPPER;
062: if (requiredCase.equalsIgnoreCase("UpperCase")) {
063: userIdentifierCase = CASE_UPPER;
064: } else if (requiredCase.equalsIgnoreCase("LowerCase")) {
065: userIdentifierCase = CASE_LOWER;
066: } else if (requiredCase.equalsIgnoreCase("PreserveCase")) {
067: userIdentifierCase = CASE_PRESERVE;
068: }
069:
070: if (userIdentifierCase == CASE_UPPER) {
071: if (dba.isStoresUpperCaseIdentifiers()) {
072: identifierCase = IdentifierFactory.IDENTIFIER_UPPER_CASE;
073: } else if (dba.isStoresUpperCaseQuotedIdentifiers()) {
074: identifierCase = IdentifierFactory.IDENTIFIER_UPPER_CASE_QUOTED;
075: } else if (dba.isStoresMixedCaseIdentifiers()) {
076: identifierCase = IdentifierFactory.IDENTIFIER_UPPER_CASE;
077: } else if (dba.isStoresMixedCaseQuotedIdentifiers()) {
078: identifierCase = IdentifierFactory.IDENTIFIER_UPPER_CASE_QUOTED;
079: } else {
080: if (dba.isStoresLowerCaseIdentifiers()) {
081: identifierCase = IdentifierFactory.IDENTIFIER_LOWER_CASE;
082: JPOXLogger.PERSISTENCE.warn(LOCALISER.msg("039001",
083: "UPPERCASE", "LOWERCASE"));
084: } else if (dba.isStoresLowerCaseQuotedIdentifiers()) {
085: identifierCase = IdentifierFactory.IDENTIFIER_LOWER_CASE_QUOTED;
086: JPOXLogger.PERSISTENCE.warn(LOCALISER.msg("039001",
087: "UPPERCASE", "LOWERCASEQUOTED"));
088: } else {
089: // Should never happen since we've tried all options
090: throw new JPOXUserException(LOCALISER.msg("039002",
091: "UPPERCASE")).setFatal();
092: }
093: }
094: } else if (userIdentifierCase == CASE_LOWER) {
095: if (dba.isStoresLowerCaseIdentifiers()) {
096: identifierCase = IdentifierFactory.IDENTIFIER_LOWER_CASE;
097: } else if (dba.isStoresLowerCaseQuotedIdentifiers()) {
098: identifierCase = IdentifierFactory.IDENTIFIER_LOWER_CASE_QUOTED;
099: } else if (dba.isStoresMixedCaseIdentifiers()) {
100: identifierCase = IdentifierFactory.IDENTIFIER_LOWER_CASE;
101: } else if (dba.isStoresMixedCaseQuotedIdentifiers()) {
102: identifierCase = IdentifierFactory.IDENTIFIER_LOWER_CASE_QUOTED;
103: } else {
104: if (dba.isStoresUpperCaseIdentifiers()) {
105: identifierCase = IdentifierFactory.IDENTIFIER_UPPER_CASE;
106: JPOXLogger.PERSISTENCE.warn(LOCALISER.msg("039001",
107: "LOWERCASE", "UPPERCASE"));
108: } else if (dba.isStoresUpperCaseQuotedIdentifiers()) {
109: identifierCase = IdentifierFactory.IDENTIFIER_UPPER_CASE_QUOTED;
110: JPOXLogger.PERSISTENCE.warn(LOCALISER.msg("039001",
111: "LOWERCASE", "UPPERCASEQUOTED"));
112: } else {
113: // Should never happen since we've tried all options
114: throw new JPOXUserException(LOCALISER.msg("039002",
115: "LOWERCASE")).setFatal();
116: }
117: }
118: } else if (userIdentifierCase == CASE_PRESERVE) {
119: if (dba.isStoresMixedCaseIdentifiers()) {
120: identifierCase = IdentifierFactory.IDENTIFIER_MIXED_CASE;
121: } else if (dba.isStoresMixedCaseQuotedIdentifiers()) {
122: identifierCase = IdentifierFactory.IDENTIFIER_MIXED_CASE_QUOTED;
123: } else {
124: if (dba.isStoresLowerCaseIdentifiers()) {
125: identifierCase = IdentifierFactory.IDENTIFIER_LOWER_CASE;
126: JPOXLogger.PERSISTENCE.warn(LOCALISER.msg("039001",
127: "MIXEDCASE", "LOWERCASE"));
128: } else if (dba.isStoresLowerCaseQuotedIdentifiers()) {
129: identifierCase = IdentifierFactory.IDENTIFIER_LOWER_CASE_QUOTED;
130: JPOXLogger.PERSISTENCE.warn(LOCALISER.msg("039001",
131: "MIXEDCASE", "LOWERCASEQUOTED"));
132: } else if (dba.isStoresUpperCaseIdentifiers()) {
133: identifierCase = IdentifierFactory.IDENTIFIER_UPPER_CASE;
134: JPOXLogger.PERSISTENCE.warn(LOCALISER.msg("039001",
135: "MIXEDCASE", "UPPERCASE"));
136: } else if (dba.isStoresUpperCaseQuotedIdentifiers()) {
137: identifierCase = IdentifierFactory.IDENTIFIER_UPPER_CASE_QUOTED;
138: JPOXLogger.PERSISTENCE.warn(LOCALISER.msg("039001",
139: "MIXEDCASE", "UPPERCASEQUOTED"));
140: } else {
141: // Should never happen since we've tried all options
142: throw new JPOXUserException(LOCALISER.msg("039002",
143: "MIXEDCASE")).setFatal();
144: }
145: }
146: } else {
147: // Case not supported
148: throw new JPOXUserException(LOCALISER.msg("039000",
149: userIdentifierCase)).setFatal();
150: }
151: }
152:
153: /**
154: * Accessor for the datastore adapter that we are creating identifiers for.
155: * @return The datastore adapter
156: */
157: public DatastoreAdapter getDatastoreAdapter() {
158: return dba;
159: }
160:
161: /**
162: * Accessor for the identifier case being used.
163: * @return The identifier case
164: */
165: public int getIdentifierCase() {
166: return identifierCase;
167: }
168:
169: /**
170: * Convenience method to return the name for the identifier case.
171: * @return Identifier case name
172: */
173: public String getNameOfIdentifierCase() {
174: if (identifierCase == IDENTIFIER_LOWER_CASE) {
175: return "lowercase";
176: } else if (identifierCase == IDENTIFIER_LOWER_CASE_QUOTED) {
177: return "\"lowercase\"";
178: } else if (identifierCase == IDENTIFIER_MIXED_CASE) {
179: return "\"MixedCase\"";
180: } else if (identifierCase == IDENTIFIER_MIXED_CASE_QUOTED) {
181: return "\"MixedCase\"";
182: } else if (identifierCase == IDENTIFIER_UPPER_CASE) {
183: return "UPPERCASE";
184: } else if (identifierCase == IDENTIFIER_UPPER_CASE_QUOTED) {
185: return "\"UPPERCASE\"";
186: } else {
187: return "UNKNOWN";
188: }
189: }
190:
191: /**
192: * Method to truncate an identifier to fit within the specified identifier length.
193: * If truncation is necessary will use a 2 char hashcode (at the end) to attempt to create uniqueness.
194: * @param identifier The identifier
195: * @param length The (max) length to use
196: * @return The truncated identifier.
197: */
198: protected static String truncate(String identifier, int length) {
199: if (identifier.length() > length) {
200: // Truncation is necessary so cut down to "maxlength-2" and add 2 char hashcode
201: int tailIndex = length - 2;
202: int tailHash = identifier.substring(tailIndex).hashCode();
203:
204: // Scale the hash code down to the range 0 - 1295
205: if (tailHash < 0) {
206: tailHash = tailHash % HASH_RANGE + (HASH_RANGE - 1);
207: } else {
208: tailHash = tailHash % HASH_RANGE + HASH_RANGE;
209: }
210:
211: String suffix = "0"
212: + Integer.toString(tailHash, Character.MAX_RADIX);
213:
214: return identifier.substring(0, tailIndex)
215: + suffix.substring(suffix.length() - 2);
216: } else {
217: return identifier;
218: }
219: }
220:
221: /**
222: * Method to return the maximum permitted length of an identifier of the
223: * specified type. Returns -1 if the identifier type is not supported.
224: * @param identifierType Type of identifier
225: * @return The maximum length
226: */
227: protected abstract int getMaxLengthForIdentifierType(
228: int identifierType);
229: }
|