Java tutorial
/* * Copyright 2004-2014 the Seasar Foundation and the Others. * * Licensed 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.seasar.dbflute; import java.util.Date; import java.util.List; import java.util.TimeZone; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.seasar.dbflute.dbmeta.accessory.EntityModifiedProperties; import org.seasar.dbflute.exception.CharParameterShortSizeException; import org.seasar.dbflute.exception.NonSpecifiedColumnAccessException; import org.seasar.dbflute.exception.UndefinedClassificationCodeException; import org.seasar.dbflute.exception.factory.ExceptionMessageBuilder; import org.seasar.dbflute.jdbc.Classification; import org.seasar.dbflute.jdbc.ClassificationMeta; import org.seasar.dbflute.jdbc.ClassificationUndefinedHandlingType; import org.seasar.dbflute.jdbc.ParameterUtil.ShortCharHandlingMode; import org.seasar.dbflute.resource.DBFluteSystem; import org.seasar.dbflute.util.DfTypeUtil; import org.seasar.dbflute.util.Srl; /** * The FunCustodial provides small services to your entities. * @author jflute * @since 1.1.0 (2014/10/18 Saturday) */ public class FunCustodial { // =================================================================================== // Definition // ========== /** The instance of logging object for classification meta. (NotNull) */ private static final Log _clsMetaLog = LogFactory.getLog(ClassificationMeta.class); // =================================================================================== // Value Conversion // ================ public static String toClassTitle(Object entity) { return DfTypeUtil.toClassTitle(entity); } @SuppressWarnings("unchecked") public static <NUMBER extends Number> NUMBER toNumber(Object obj, Class<NUMBER> type) { return (NUMBER) DfTypeUtil.toNumber(obj, type); } public static Boolean toBoolean(Object obj) { return DfTypeUtil.toBoolean(obj); } public static String toStringDate(Date date, String pattern, TimeZone timeZone) { if (date == null) { return null; } final TimeZone realZone = timeZone != null ? timeZone : DBFluteSystem.getFinalTimeZone(); final String str = DfTypeUtil.toStringDate(date, pattern, realZone); return (DfTypeUtil.isDateBC(date) ? "BC" : "") + str; } public static String toStringBytes(byte[] bytes) { return "byte[" + (bytes != null ? String.valueOf(bytes.length) : "null") + "]"; } public static String convertEmptyToNull(String value) { return (value != null && value.length() == 0) ? null : value; } // ----------------------------------------------------- // Short Character // --------------- /** * @param parameterName The name of the parameter. (NotNull) * @param value The value of the parameter. (NullAllowed) * @param size The size of parameter type. (NullAllowed) * @param mode The handling mode. (NotNull) * @return The filtered value. (NullAllowed) */ public static String handleShortChar(String parameterName, String value, Integer size, ShortCharHandlingMode mode) { if (parameterName == null || parameterName.trim().length() == 0) { String msg = "The argument 'parameterName' should not be null or empty:"; msg = msg + " value=" + value + " size=" + size + " mode=" + mode; throw new IllegalArgumentException(msg); } if (mode == null) { String msg = "The argument 'mode' should not be null:"; msg = msg + " parameterName=" + parameterName + " value=" + value + " size=" + size; throw new IllegalArgumentException(msg); } if (value == null) { return null; } if (size == null) { return value; } if (value.length() >= size) { return value; } if (mode.equals(ShortCharHandlingMode.RFILL)) { return Srl.rfill(value, size); } else if (mode.equals(ShortCharHandlingMode.LFILL)) { return Srl.lfill(value, size); } else if (mode.equals(ShortCharHandlingMode.EXCEPTION)) { String msg = "The size of the parameter '" + parameterName + "' should be " + size + ":"; msg = msg + " value=[" + value + "] size=" + value.length(); throw new CharParameterShortSizeException(msg); } else { return value; } } // =================================================================================== // Specified Properties // ==================== public static void checkSpecifiedProperty(Entity entity, String propertyName, EntityModifiedProperties specifiedProperties) { if (specifiedProperties == null) { // means no need to check (e.g. all columns are selected) return; } if (!entity.createdBySelect()) { // basically no way, selected when the properties exists but just in case return; } // SpecifyColumn is used for the entity if (specifiedProperties.isModifiedProperty(propertyName)) { // yes, setter is called when select mapping return; // OK, OK } // no, you get the non-specified column, throws exception throwNonSpecifiedColumnAccessException(entity, propertyName, specifiedProperties); } protected static void throwNonSpecifiedColumnAccessException(Entity entity, String propertyName, EntityModifiedProperties specifiedProperties) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice("Non-specified column was accessed."); br.addItem("Advice"); br.addElement("To get non-specified column from entity is not allowd."); br.addElement("Non-specified means using SpecifyColumn but the column is non-specified."); br.addElement("Mistake? Or specify the column by your condition-bean if you need it."); br.addElement("For example:"); br.addElement(" (x):"); br.addElement(" memberBhv.selectEntity(cb -> {"); br.addElement(" cb.setupSelect_MemberStatus();"); br.addElement(" cb.specify().columnMemberStatusName();"); br.addElement(" cb.query().set..."); br.addElement(" }).alwaysPresent(member -> {"); br.addElement(" member.getMemberStatus().alwaysPresent(status -> {"); br.addElement(" ... = status.getMemberStatusName(); // OK"); br.addElement(" ... = status.getDisplayOrder(); // *NG: exception"); br.addElement(" });"); br.addElement(" });"); br.addElement(" (o):"); br.addElement(" memberBhv.selectEntity(cb -> {"); br.addElement(" cb.setupSelect_MemberStatus();"); br.addElement(" cb.specify().columnMemberStatusName();"); br.addElement(" cb.specify().columnDisplayOrder(); // *Point"); br.addElement(" cb.query().set..."); br.addElement(" }).alwaysPresent(member -> {"); br.addElement(" member.getMemberStatus().alwaysPresent(status -> {"); br.addElement(" ... = status.getMemberStatusName(); // OK"); br.addElement(" ... = status.getDisplayOrder(); // OK"); br.addElement(" });"); br.addElement(" });"); br.addElement(""); br.addElement("While, reluctantly you need to get the column without change conditions,"); br.addElement("you can enable non-specified column access by the condition-bean option."); br.addElement("The method is cb.enable...()"); buildExceptionTableInfo(br, entity); br.addItem("Non-Specified and Accessed"); br.addElement(propertyName); br.addItem("Specified Column in the Table"); br.addElement(specifiedProperties); final String msg = br.buildExceptionMessage(); throw new NonSpecifiedColumnAccessException(msg); } protected static void buildExceptionTableInfo(ExceptionMessageBuilder br, Entity entity) { br.addItem("Table"); br.addElement(entity.getTableDbName()); try { br.addElement(entity.getDBMeta().extractPrimaryKeyMap(entity)); } catch (RuntimeException continued) { // just in case br.addElement("*Failed to get PK info:"); br.addElement(continued.getMessage()); } } // =================================================================================== // Classification // ============== public static void checkClassificationCode(Entity entity, String columnDbName, ClassificationMeta meta, Object code) { if (code == null) { return; } final ClassificationUndefinedHandlingType undefinedHandlingType = meta.undefinedHandlingType(); if (!undefinedHandlingType.isChecked()) { // basically no way (not called if no check) return; } if (meta.codeOf(code) != null) { return; } handleUndefinedClassificationCode(entity.getTableDbName(), columnDbName, meta, code); } public static void handleUndefinedClassificationCode(String tableDbName, String columnDbName, ClassificationMeta meta, Object code) { final ClassificationUndefinedHandlingType undefinedHandlingType = meta.undefinedHandlingType(); if (ClassificationUndefinedHandlingType.EXCEPTION.equals(undefinedHandlingType)) { throwUndefinedClassificationCodeException(tableDbName, columnDbName, meta, code); } else if (ClassificationUndefinedHandlingType.LOGGING.equals(undefinedHandlingType)) { showUndefinedClassificationCodeMessage(tableDbName, columnDbName, meta, code); } // else means ALLOWED } protected static void throwUndefinedClassificationCodeException(String tableDbName, String columnDbName, ClassificationMeta meta, Object code) { final ExceptionMessageBuilder br = new ExceptionMessageBuilder(); br.addNotice("Undefined classification code was set to the entity."); br.addItem("Advice"); br.addElement("Confirm the value of the classication column on your database,"); br.addElement("or setting value to your entity."); br.addElement("The code is NOT one of classification code defined on DBFlute."); br.addElement(""); br.addElement("_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/"); br.addElement(" Use formal code!"); br.addElement(" Or add the code to classification definition."); br.addElement("_/_/_/_/_/_/_/_/_/_/"); br.addElement(""); br.addElement("Or if you (reluctantly) need to allow it, change the option like this:"); br.addElement("but *Deprecated"); br.addElement("(classificationDefinitionMap.dfprop)"); br.addElement(" ; [classification-name] = list:{"); br.addElement(" ; map:{"); br.addElement(" ; topComment=...; codeType=..."); br.addElement(" ; undefinedHandlingType=ALLOWED"); br.addElement(" }"); br.addElement(" map:{...}"); br.addElement(" }"); br.addElement("*for your information, the default of undefinedHandlingType is LOGGING"); br.addItem("Table"); br.addElement(tableDbName); br.addItem("Column"); br.addElement(columnDbName); br.addItem("Classification"); br.addElement(meta.classificationName()); final List<Classification> listAll = meta.listAll(); final StringBuilder sb = new StringBuilder(); for (Classification cls : listAll) { if (sb.length() > 0) { sb.append(", "); } sb.append(cls.name()).append("(").append(cls.code()).append(")"); } br.addElement(sb.toString()); br.addItem("Undefined Code"); br.addElement(code); final String msg = br.buildExceptionMessage(); throw new UndefinedClassificationCodeException(msg); } public static void showUndefinedClassificationCodeMessage(String tableDbName, String columnDbName, ClassificationMeta meta, Object code) { if (_clsMetaLog.isInfoEnabled()) { final String classificationName = meta.classificationName(); final String exp = tableDbName + "." + columnDbName + "->" + classificationName + "." + code; _clsMetaLog.info("*Undefined classification code was set: " + exp); // one line because of many called } } // =================================================================================== // Small Helper // ============ // ------------ public static boolean isSameValue(Object value1, Object value2) { if (value1 == null && value2 == null) { return true; } if (value1 == null || value2 == null) { return false; } if (value1 instanceof byte[] && value2 instanceof byte[]) { return isSameValueBytes((byte[]) value1, (byte[]) value2); } return value1.equals(value2); } public static boolean isSameValueBytes(byte[] bytes1, byte[] bytes2) { if (bytes1 == null && bytes2 == null) { return true; } if (bytes1 == null || bytes2 == null) { return false; } if (bytes1.length != bytes2.length) { return false; } for (int i = 0; i < bytes1.length; i++) { if (bytes1[i] != bytes2[i]) { return false; } } return true; } public static int calculateHashcode(int result, Object value) { // calculateHashcode() if (value == null) { return result; } return (31 * result) + (value instanceof byte[] ? ((byte[]) value).length : value.hashCode()); } }