Java tutorial
/* * (C) Copyright 2014, 2016 Nuxeo SA (http://nuxeo.com/) and 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.nuxeo.runtime.datasource; import java.sql.SQLException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.commons.logging.LogFactory; import org.nuxeo.common.xmap.annotation.XNode; import org.nuxeo.common.xmap.annotation.XNodeList; import org.nuxeo.common.xmap.annotation.XObject; import org.nuxeo.runtime.model.ContributionFragmentRegistry; import org.tranql.connector.ExceptionSorter; /** * * * @since 8.3 */ public class DatasourceExceptionSorter implements ExceptionSorter { public enum Classcode { NoError("00"), Warning("01"), NoData("02"), DynamicSQLError("07"), ConnectionException( "08"), TriggeredActionException("09"), FeatureNotSupported("0A"), InvalidTransactionInitiation( "0B"), InvalidTargetTypeSpecification("0D"), InvalidSchemaNameListSpecification( "0E"), LocatorException("0F"), ResignalWhenHandlerNotActive( "0K"), InvalidGrantor("0L"), InvalidSqlInvokedProcedureReference( "0M"), MappingError("0N"), InvalidRoleSpecification( "0P"), InvalidTransformGroupNameSpecification( "0S"), TargetTableDisagreesWithCursorSpecification( "0T"), AttemptToAssignNonUpdatableColumn( "0U"), AttemptToAssignToOrderingColumn( "0V"), ProhibitedStatementEncouteredDuringTriggerExecution( "0W"), DiagnosticsException( "0Z"), XQuery( "10"), CaseNotFoundInCaseStatement( "20"), CardinalityViolation( "21"), DataException( "22"), IntegrityConstraintViolation( "23"), InvalidCursorState( "24"), InvalidTransactionState( "25"), InvalidSQLStatementName( "26"), TriggeredDataChangeViolation( "27"), InvalidAuthorizationSpeciciation( "28"), DependentPrivilegeDescriptorsAlreadyExsist( "2B"), InvalidConnectionName( "2E"), InvalidCharacterSetName( "2C"), InvalidTransactionTermination( "2D"), SqlRoutineException( "2F"), InvalidSessionCollationSpecication( "2H"), InvalidSqlStatementIdentifier( "30"), InvalidSqlDescriptorName( "33"), InvalidCursorName( "34"), InvalidConditionNumber( "35"), CursorSensivityException( "36"), SyntaxError( "37"), ExternalRoutineException( "38"), ExternalRoutineInvocationException( "39"), SavepointException( "3B"), InvalidCatalogName( "3D"), AmbiguousCursorName( "3C"), InvalidSchemaName( "3F"), TransactionRollback( "40"), SyntaxErrorOrAccessRuleViolation( "42"), WithCheckOptionViolation( "44"), JavaErrors( "46"), InvalidApplicationState( "51"), InvalidOperandOrInconsistentSpecification( "53"), SqlOrProductLimitExcedeed( "54"), ObjectNotInPrerequisiteState( "55"), MiscellaneoudSqlOrProductError( "56"), ResourceNotAvailableOrOperatorIntervention( "57"), SystemError( "58"), CommonUtilitiesAndTools( "5U"), RemoteDatabaseAccess( "HZ"); public String value; Classcode(String code) { value = code; } } @XObject("sorter") public static class Configuration { @XNode("@id") String id = ""; @XNode("@override") boolean override = false; @XNode("@path") String pathname; boolean matches(String classname) { return classname.startsWith(pathname); } @XNodeList(value = "code", type = String[].class, componentType = String.class) public void setCodes(String... values) { for (String value : values) { Classcode classcode = Classcode.valueOf(value); if (classcode != null) { value = classcode.value; } int length = value.length(); if (length == 2) { codes.add(value); } else if (length == 5) { states.add(value); } else { LogFactory.getLog(DatasourceExceptionSorter.class).error("invalid code " + value); } } } final Set<String> codes = new HashSet<>(); final Set<String> states = new HashSet<>(); @XNodeList(value = "vendor", type = HashSet.class, componentType = Integer.class) Set<Integer> vendors = new HashSet<>(); boolean isFatal(String sqlstate, Integer vendor) { String code = sqlstate.substring(0, 2); return codes.contains(code) || states.contains(sqlstate) || vendors.contains(vendor); } } public static class Registry extends ContributionFragmentRegistry<Configuration> { final Map<String, Configuration> actuals = new HashMap<>(); @Override public String getContributionId(Configuration contrib) { return contrib.id; } @Override public void contributionUpdated(String id, Configuration contrib, Configuration newOrigContrib) { actuals.put(id, contrib); } @Override public void contributionRemoved(String id, Configuration origContrib) { actuals.put(id, origContrib); } @Override public Configuration clone(Configuration orig) { Configuration cloned = new Configuration(); cloned.states.addAll(orig.states); cloned.codes.addAll(orig.codes); return cloned; } @Override public void merge(Configuration src, Configuration dst) { if (src.override) { dst.states.clear(); dst.codes.clear(); } dst.states.addAll(src.states); dst.codes.addAll(src.codes); } public Configuration lookup(SQLException se) { for (StackTraceElement frame : se.getStackTrace()) { for (Configuration config : actuals.values()) { if ("".equals(config.id)) { continue; } if (config.matches(frame.getClassName())) { return config; } } } return actuals.get(""); } } Configuration configuration; @Override public boolean isExceptionFatal(Exception e) { if (!(e instanceof SQLException)) { return true; } SQLException se = (SQLException) e; String statuscode = se.getSQLState(); Integer errorcode = Integer.valueOf(se.getErrorCode()); if (configuration == null) { configuration = DataSourceComponent.instance.sorterRegistry.lookup(se); } return configuration.isFatal(statuscode, errorcode); } @Override public boolean rollbackOnFatalException() { return true; } }