/* * 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.persistence; import java.util.HashMap; import java.util.Locale; import java.util.Map; import javax.persistence.CacheRetrieveMode; import javax.persistence.CacheStoreMode; import org.apache.openjpa.lib.util.StringUtil; import org.apache.openjpa.kernel.DataCacheRetrieveMode; import org.apache.openjpa.kernel.DataCacheStoreMode; /** * Enumerates configuration property keys defined in JPA 2.0 Specification. * <br> * Provides static utility functions to read their values from supplied map of properties. * <br> * Provides static utility functions to convert them to values that are fit for OpenJPA implementation. * <br> * @author Pinaki Poddar * @since 2.0.0 * */ public class JPAProperties { private static final String REGEX_DOT = "\\."; public static final String PREFIX = "javax.persistence."; public static final String PROVIDER = PREFIX + "provider"; public static final String TRANSACTION_TYPE = PREFIX + "transactionType"; public static final String DATASOURCE = PREFIX + "dataSource"; public static final String DATASOURCE_JTA = PREFIX + "jtaDataSource"; public static final String DATASOURCE_NONJTA = PREFIX + "nonJtaDataSource"; public static final String JDBC_DRIVER = PREFIX + "jdbc.driver"; public static final String JDBC_URL = PREFIX + "jdbc.url"; public static final String JDBC_USER = PREFIX + "jdbc.user"; public static final String JDBC_PASSWORD = PREFIX + "jdbc.password"; public static final String LOCK_SCOPE = PREFIX + "lock.scope"; public static final String LOCK_TIMEOUT = PREFIX + "lock.timeout"; public static final String QUERY_TIMEOUT = PREFIX + "query.timeout"; public static final String CACHE_MODE = PREFIX + "sharedCache.mode"; public static final String CACHE_STORE_MODE = PREFIX + "cache.storeMode"; public static final String CACHE_RETRIEVE_MODE = PREFIX + "cache.retrieveMode"; public static final String VALIDATE_FACTORY = PREFIX + "validation.factory"; public static final String VALIDATE_MODE = PREFIX + "validation.mode"; public static final String VALIDATE_PRE_PERSIST = PREFIX + "validation.group.pre-persist"; public static final String VALIDATE_PRE_REMOVE = PREFIX + "validation.group.pre-remove"; public static final String VALIDATE_PRE_UPDATE = PREFIX + "validation.group.pre-update"; public static final String VALIDATE_GROUP_DEFAULT = "javax.validation.groups.Default"; private static Map<String,String> _names = new HashMap<String, String>(); /** * Record the given kernel property key (which is a bean property name without any suffix) * corresponding to the given original JPA/OpenJPA property used by the user to set the values. */ static void record(String kernel, String user) { _names.put(kernel, user); } /** * Gets the original JPA Property name corresponding to the kernel property key * (which is a bean property name without any suffix). */ static String getUserName(String beanProperty) { return _names.containsKey(beanProperty) ? _names.get(beanProperty) : beanProperty; } /** * Is the given key appears to be a valid JPA specification defined key? * * @return true if the given string merely prefixed with <code>javax.persistence.</code>. * Does not really check all the keys defined in the specification. */ public static boolean isValidKey(String key) { return key != null && key.startsWith(PREFIX); } /** * Gets a bean-style property name from the given key. * * @param key must begin with JPA property prefix <code>javax.persistence</code> * * @return concatenates each part of the string leaving out <code>javax.persistence.</code> prefix. * Part of string is what appears between DOT character. */ public static String getBeanProperty(String key) { if (!isValidKey(key)) throw new IllegalArgumentException("Invalid JPA property " + key); String[] parts = key.split(REGEX_DOT); StringBuilder buf = new StringBuilder(); for (int i = 2; i < parts.length; i++) { buf.append(StringUtil.capitalize(parts[i])); } return buf.toString(); } /** * Convert the given user value to a value consumable by OpenJPA kernel constructs. * * @return the same value if the given key is not a valid JPA property key or the value is null. */ public static <T> T convertToKernelValue(Class<T> resultType, String key, Object value) { if (value == null) return null; if (JPAProperties.isValidKey(key)) { // works because enum values are identical String if (value instanceof CacheRetrieveMode || (value instanceof String && CACHE_RETRIEVE_MODE.equals(key))) { return (T)DataCacheRetrieveMode.valueOf(value.toString().trim().toUpperCase(Locale.ENGLISH)); } else if (value instanceof CacheStoreMode || (value instanceof String && CACHE_STORE_MODE.equals(key))) { return (T)DataCacheStoreMode.valueOf(value.toString().trim().toUpperCase(Locale.ENGLISH)); } } return (T)value; } /** * Convert the given kernel value to a value visible to the user. * * @return the same value if the given key is not a valid JPA property key or the value is null. */ public static Object convertToUserValue(String key, Object value) { if (value == null) return null; if (JPAProperties.isValidKey(key)) { // works because enum values are identical String if (value instanceof DataCacheRetrieveMode) { return CacheRetrieveMode.valueOf(value.toString().trim().toUpperCase(Locale.ENGLISH)); } else if (value instanceof DataCacheStoreMode) { return CacheStoreMode.valueOf(value.toString().trim().toUpperCase(Locale.ENGLISH)); } } return value; } /** * Get the value of the given key from the given properties after converting it to the given * enumerated value. */ public static <E extends Enum<E>> E getEnumValue(Class<E> type, String key, Map<String,Object> prop) { return getEnumValue(type, null, key, prop); } /** * Gets a enum value of the given type from the given properties looking up with the given key. * Converts the original value from a String or ordinal number, if necessary. * Conversion from an integral number to enum value is only attempted if the allowed enum values * are provided as non-null, non-empty array. * * @return null if the key does not exist in the given properties. */ public static <E extends Enum<E>> E getEnumValue(Class<E> type, E[] values, String key, Map<String,Object> prop) { if (prop == null) return null; return getEnumValue(type, values, prop.get(key)); } /** * Gets a enum value of the given type from the given value. * Converts the original value from a String, if necessary. * * @return null if the key does not exist in the given properties. */ public static <E extends Enum<E>> E getEnumValue(Class<E> type, Object val) { return getEnumValue(type, null, val); } /** * Gets a enum value of the given type from the given value. * Converts the original value from a String or ordinal number, if necessary. * Conversion from an integral number to enum value is only attempted if the allowed enum values * are provided as non-null, non-empty array. * * @return null if the key does not exist in the given properties. */ public static <E extends Enum<E>> E getEnumValue(Class<E> type, E[] values, Object val) { if (val == null) return null; if (type.isInstance(val)) return (E)val; if (val instanceof String) { return Enum.valueOf(type, val.toString().trim().toUpperCase(Locale.ENGLISH)); } if (values != null && values.length > 0 && val instanceof Number) { return values[((Number)val).intValue()]; } return null; } }