Java tutorial
/* * Copyright (c) 2010-2014 Evolveum * * 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 com.evolveum.midpoint.repo.sql; import com.evolveum.midpoint.common.InternalsConfig; import com.evolveum.midpoint.common.crypto.CryptoUtil; import com.evolveum.midpoint.prism.ConsistencyCheckScope; import com.evolveum.midpoint.prism.Containerable; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismProperty; import com.evolveum.midpoint.prism.PrismPropertyValue; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.PropertyDelta; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.polystring.PolyString; import com.evolveum.midpoint.prism.query.AllFilter; import com.evolveum.midpoint.prism.query.NoneFilter; import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.prism.query.ObjectPaging; import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.repo.api.RepoAddOptions; import com.evolveum.midpoint.repo.api.RepositoryService; import com.evolveum.midpoint.repo.sql.helpers.ObjectRetriever; import com.evolveum.midpoint.repo.sql.helpers.ObjectUpdater; import com.evolveum.midpoint.repo.sql.helpers.OrgClosureManager; import com.evolveum.midpoint.repo.sql.helpers.SequenceHelper; import com.evolveum.midpoint.schema.GetOperationOptions; import com.evolveum.midpoint.schema.LabeledString; import com.evolveum.midpoint.schema.RepositoryDiag; import com.evolveum.midpoint.schema.ResultHandler; import com.evolveum.midpoint.schema.SearchResultList; import com.evolveum.midpoint.schema.SearchResultMetadata; import com.evolveum.midpoint.schema.SelectorOptions; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.result.OperationResultStatus; import com.evolveum.midpoint.schema.util.ObjectQueryUtil; import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; import org.apache.commons.lang.Validate; import org.hibernate.Session; import org.hibernate.internal.SessionFactoryImpl; import org.hibernate.jdbc.Work; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; import java.util.List; import java.util.Properties; /** * @author lazyman */ @Repository public class SqlRepositoryServiceImpl extends SqlBaseService implements RepositoryService { public static final String PERFORMANCE_LOG_NAME = SqlRepositoryServiceImpl.class.getName() + ".performance"; private static final Trace LOGGER = TraceManager.getTrace(SqlRepositoryServiceImpl.class); private static final Trace LOGGER_PERFORMANCE = TraceManager.getTrace(PERFORMANCE_LOG_NAME); public static final int MAX_CONSTRAINT_NAME_LENGTH = 40; private static final String IMPLEMENTATION_SHORT_NAME = "SQL"; private static final String IMPLEMENTATION_DESCRIPTION = "Implementation that stores data in generic relational" + " (SQL) databases. It is using ORM (hibernate) on top of JDBC to access the database."; private static final String DETAILS_TRANSACTION_ISOLATION = "transactionIsolation"; private static final String DETAILS_CLIENT_INFO = "clientInfo."; private static final String DETAILS_DATA_SOURCE = "dataSource"; private static final String DETAILS_HIBERNATE_DIALECT = "hibernateDialect"; private static final String DETAILS_HIBERNATE_HBM_2_DDL = "hibernateHbm2ddl"; @Autowired private SequenceHelper sequenceHelper; @Autowired private ObjectRetriever objectRetriever; @Autowired private ObjectUpdater objectUpdater; @Autowired private OrgClosureManager closureManager; public SqlRepositoryServiceImpl(SqlRepositoryFactory repositoryFactory) { super(repositoryFactory); } // public because of testing public OrgClosureManager getClosureManager() { return closureManager; } @Override public <T extends ObjectType> PrismObject<T> getObject(Class<T> type, String oid, Collection<SelectorOptions<GetOperationOptions>> options, OperationResult result) throws ObjectNotFoundException, SchemaException { Validate.notNull(type, "Object type must not be null."); Validate.notEmpty(oid, "Oid must not be null or empty."); Validate.notNull(result, "Operation result must not be null."); LOGGER.debug("Getting object '{}' with oid '{}'.", new Object[] { type.getSimpleName(), oid }); final String operation = "getting"; int attempt = 1; OperationResult subResult = result.createMinorSubresult(GET_OBJECT); subResult.addParam("type", type.getName()); subResult.addParam("oid", oid); SqlPerformanceMonitor pm = getPerformanceMonitor(); long opHandle = pm.registerOperationStart("getObject"); try { while (true) { try { return objectRetriever.getObjectAttempt(type, oid, options, subResult); } catch (RuntimeException ex) { attempt = logOperationAttempt(oid, operation, attempt, ex, subResult); pm.registerOperationNewTrial(opHandle, attempt); } } } finally { pm.registerOperationFinish(opHandle, attempt); } } @Override public <F extends FocusType> PrismObject<F> searchShadowOwner(String shadowOid, Collection<SelectorOptions<GetOperationOptions>> options, OperationResult result) { Validate.notEmpty(shadowOid, "Oid must not be null or empty."); Validate.notNull(result, "Operation result must not be null."); LOGGER.debug("Searching shadow owner for {}", shadowOid); final String operation = "searching shadow owner"; int attempt = 1; OperationResult subResult = result.createSubresult(SEARCH_SHADOW_OWNER); subResult.addParam("shadowOid", shadowOid); while (true) { try { return objectRetriever.searchShadowOwnerAttempt(shadowOid, options, subResult); } catch (RuntimeException ex) { attempt = logOperationAttempt(shadowOid, operation, attempt, ex, subResult); } } } @Override @Deprecated public PrismObject<UserType> listAccountShadowOwner(String accountOid, OperationResult result) throws ObjectNotFoundException { Validate.notEmpty(accountOid, "Oid must not be null or empty."); Validate.notNull(result, "Operation result must not be null."); LOGGER.debug("Selecting account shadow owner for account {}.", new Object[] { accountOid }); final String operation = "listing account shadow owner"; int attempt = 1; OperationResult subResult = result.createSubresult(LIST_ACCOUNT_SHADOW); subResult.addParam("accountOid", accountOid); while (true) { try { return objectRetriever.listAccountShadowOwnerAttempt(accountOid, subResult); } catch (RuntimeException ex) { attempt = logOperationAttempt(accountOid, operation, attempt, ex, subResult); } } } @Override public <T extends ObjectType> SearchResultList<PrismObject<T>> searchObjects(Class<T> type, ObjectQuery query, Collection<SelectorOptions<GetOperationOptions>> options, OperationResult result) throws SchemaException { Validate.notNull(type, "Object type must not be null."); Validate.notNull(result, "Operation result must not be null."); logSearchInputParameters(type, query, false, null); OperationResult subResult = result.createSubresult(SEARCH_OBJECTS); subResult.addParam("type", type.getName()); subResult.addParam("query", query); // subResult.addParam("paging", paging); if (query != null) { ObjectFilter filter = query.getFilter(); filter = ObjectQueryUtil.simplify(filter); if (filter instanceof NoneFilter) { subResult.recordSuccess(); return new SearchResultList(new ArrayList<PrismObject<T>>(0)); } else if (filter instanceof AllFilter) { query = query.cloneEmpty(); query.setFilter(null); } else { query = query.cloneEmpty(); query.setFilter(filter); } } SqlPerformanceMonitor pm = getPerformanceMonitor(); long opHandle = pm.registerOperationStart("searchObjects"); final String operation = "searching"; int attempt = 1; try { while (true) { try { return objectRetriever.searchObjectsAttempt(type, query, options, subResult); } catch (RuntimeException ex) { attempt = logOperationAttempt(null, operation, attempt, ex, subResult); pm.registerOperationNewTrial(opHandle, attempt); } } } finally { pm.registerOperationFinish(opHandle, attempt); } } @Override public <T extends Containerable> SearchResultList<T> searchContainers(Class<T> type, ObjectQuery query, Collection<SelectorOptions<GetOperationOptions>> options, OperationResult parentResult) throws SchemaException { Validate.notNull(type, "Object type must not be null."); Validate.notNull(parentResult, "Operation result must not be null."); logSearchInputParameters(type, query, false, null); OperationResult result = parentResult.createSubresult(SEARCH_CONTAINERS); result.addParam("type", type.getName()); result.addParam("query", query); if (query != null) { ObjectFilter filter = query.getFilter(); filter = ObjectQueryUtil.simplify(filter); if (filter instanceof NoneFilter) { result.recordSuccess(); return new SearchResultList(new ArrayList<T>(0)); } else if (filter instanceof AllFilter) { query = query.cloneEmpty(); query.setFilter(null); } else { query = query.cloneEmpty(); query.setFilter(filter); } } SqlPerformanceMonitor pm = getPerformanceMonitor(); long opHandle = pm.registerOperationStart("searchContainers"); final String operation = "searching"; int attempt = 1; try { while (true) { try { return objectRetriever.searchContainersAttempt(type, query, options, result); } catch (RuntimeException ex) { attempt = logOperationAttempt(null, operation, attempt, ex, result); pm.registerOperationNewTrial(opHandle, attempt); } } } finally { pm.registerOperationFinish(opHandle, attempt); } } private <T> void logSearchInputParameters(Class<T> type, ObjectQuery query, boolean iterative, Boolean strictlySequential) { ObjectPaging paging = query != null ? query.getPaging() : null; LOGGER.debug( "Searching objects of type '{}', query (on trace level), offset {}, count {}, iterative {}, strictlySequential {}.", new Object[] { type.getSimpleName(), (paging != null ? paging.getOffset() : "undefined"), (paging != null ? paging.getMaxSize() : "undefined"), iterative, strictlySequential }); if (!LOGGER.isTraceEnabled()) { return; } LOGGER.trace("Full query\n{}\nFull paging\n{}", new Object[] { (query == null ? "undefined" : query.debugDump()), (paging != null ? paging.debugDump() : "undefined") }); if (iterative) { LOGGER.trace("Iterative search by paging: {}, batch size {}", getConfiguration().isIterativeSearchByPaging(), getConfiguration().getIterativeSearchByPagingBatchSize()); } } @Override public <T extends ObjectType> String addObject(PrismObject<T> object, RepoAddOptions options, OperationResult result) throws ObjectAlreadyExistsException, SchemaException { Validate.notNull(object, "Object must not be null."); validateName(object); Validate.notNull(result, "Operation result must not be null."); if (options == null) { options = new RepoAddOptions(); } LOGGER.debug("Adding object type '{}', overwrite={}, allowUnencryptedValues={}", new Object[] { object.getCompileTimeClass().getSimpleName(), options.isOverwrite(), options.isAllowUnencryptedValues() }); if (InternalsConfig.encryptionChecks && !RepoAddOptions.isAllowUnencryptedValues(options)) { CryptoUtil.checkEncrypted(object); } if (InternalsConfig.consistencyChecks) { object.checkConsistence(ConsistencyCheckScope.THOROUGH); } else { object.checkConsistence(ConsistencyCheckScope.MANDATORY_CHECKS_ONLY); } if (LOGGER.isTraceEnabled()) { // Explicitly log name PolyStringType namePolyType = object.asObjectable().getName(); LOGGER.trace("NAME: {} - {}", namePolyType.getOrig(), namePolyType.getNorm()); } OperationResult subResult = result.createSubresult(ADD_OBJECT); subResult.addParam("object", object); subResult.addParam("options", options); final String operation = "adding"; int attempt = 1; String oid = object.getOid(); while (true) { try { return objectUpdater.addObjectAttempt(object, options, subResult); } catch (RuntimeException ex) { attempt = logOperationAttempt(oid, operation, attempt, ex, subResult); } } } private void validateName(PrismObject object) throws SchemaException { PrismProperty name = object.findProperty(ObjectType.F_NAME); if (name == null || ((PolyString) name.getRealValue()).isEmpty()) { throw new SchemaException("Attempt to add object without name."); } } @Override public <T extends ObjectType> void deleteObject(Class<T> type, String oid, OperationResult result) throws ObjectNotFoundException { Validate.notNull(type, "Object type must not be null."); Validate.notEmpty(oid, "Oid must not be null or empty."); Validate.notNull(result, "Operation result must not be null."); LOGGER.debug("Deleting object type '{}' with oid '{}'", new Object[] { type.getSimpleName(), oid }); final String operation = "deleting"; int attempt = 1; OperationResult subResult = result.createSubresult(DELETE_OBJECT); subResult.addParam("type", type.getName()); subResult.addParam("oid", oid); SqlPerformanceMonitor pm = getPerformanceMonitor(); long opHandle = pm.registerOperationStart("deleteObject"); try { while (true) { try { objectUpdater.deleteObjectAttempt(type, oid, subResult); return; } catch (RuntimeException ex) { attempt = logOperationAttempt(oid, operation, attempt, ex, subResult); pm.registerOperationNewTrial(opHandle, attempt); } } } finally { pm.registerOperationFinish(opHandle, attempt); } } @Override public <T extends ObjectType> int countObjects(Class<T> type, ObjectQuery query, OperationResult result) { Validate.notNull(type, "Object type must not be null."); Validate.notNull(result, "Operation result must not be null."); LOGGER.debug("Counting objects of type '{}', query (on trace level).", new Object[] { type.getSimpleName() }); if (LOGGER.isTraceEnabled()) { LOGGER.trace("Full query\n{}", new Object[] { (query == null ? "undefined" : query.debugDump()) }); } OperationResult subResult = result.createMinorSubresult(COUNT_OBJECTS); subResult.addParam("type", type.getName()); subResult.addParam("query", query); if (query != null) { ObjectFilter filter = query.getFilter(); filter = ObjectQueryUtil.simplify(filter); if (filter instanceof NoneFilter) { subResult.recordSuccess(); return 0; } query = query.cloneEmpty(); query.setFilter(filter); } final String operation = "counting"; int attempt = 1; while (true) { try { return objectRetriever.countObjectsAttempt(type, query, subResult); } catch (RuntimeException ex) { attempt = logOperationAttempt(null, operation, attempt, ex, subResult); } } } @Override public <T extends ObjectType> void modifyObject(Class<T> type, String oid, Collection<? extends ItemDelta> modifications, OperationResult result) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException { Validate.notNull(modifications, "Modifications must not be null."); Validate.notNull(type, "Object class in delta must not be null."); Validate.notEmpty(oid, "Oid must not null or empty."); Validate.notNull(result, "Operation result must not be null."); OperationResult subResult = result.createSubresult(MODIFY_OBJECT); subResult.addParam("type", type.getName()); subResult.addParam("oid", oid); subResult.addCollectionOfSerializablesAsParam("modifications", modifications); if (modifications.isEmpty()) { LOGGER.debug("Modification list is empty, nothing was modified."); subResult.recordStatus(OperationResultStatus.SUCCESS, "Modification list is empty, nothing was modified."); return; } if (InternalsConfig.encryptionChecks) { CryptoUtil.checkEncrypted(modifications); } if (InternalsConfig.consistencyChecks) { ItemDelta.checkConsistence(modifications, ConsistencyCheckScope.THOROUGH); } else { ItemDelta.checkConsistence(modifications, ConsistencyCheckScope.MANDATORY_CHECKS_ONLY); } if (LOGGER.isTraceEnabled()) { for (ItemDelta modification : modifications) { if (modification instanceof PropertyDelta<?>) { PropertyDelta<?> propDelta = (PropertyDelta<?>) modification; if (propDelta.getPath().equivalent(new ItemPath(ObjectType.F_NAME))) { Collection<PrismPropertyValue<PolyString>> values = propDelta.getValues(PolyString.class); for (PrismPropertyValue<PolyString> pval : values) { PolyString value = pval.getValue(); LOGGER.trace("NAME delta: {} - {}", value.getOrig(), value.getNorm()); } } } } } final String operation = "modifying"; int attempt = 1; SqlPerformanceMonitor pm = getPerformanceMonitor(); long opHandle = pm.registerOperationStart("modifyObject"); try { while (true) { try { objectUpdater.modifyObjectAttempt(type, oid, modifications, subResult); return; } catch (RuntimeException ex) { attempt = logOperationAttempt(oid, operation, attempt, ex, subResult); pm.registerOperationNewTrial(opHandle, attempt); } } } finally { pm.registerOperationFinish(opHandle, attempt); } } @Override public <T extends ShadowType> List<PrismObject<T>> listResourceObjectShadows(String resourceOid, Class<T> resourceObjectShadowType, OperationResult result) throws ObjectNotFoundException, SchemaException { Validate.notEmpty(resourceOid, "Resource oid must not be null or empty."); Validate.notNull(resourceObjectShadowType, "Resource object shadow type must not be null."); Validate.notNull(result, "Operation result must not be null."); LOGGER.debug("Listing resource object shadows '{}' for resource '{}'.", new Object[] { resourceObjectShadowType.getSimpleName(), resourceOid }); OperationResult subResult = result.createSubresult(LIST_RESOURCE_OBJECT_SHADOWS); subResult.addParam("oid", resourceOid); subResult.addParam("resourceObjectShadowType", resourceObjectShadowType); final String operation = "listing resource object shadows"; int attempt = 1; SqlPerformanceMonitor pm = getPerformanceMonitor(); long opHandle = pm.registerOperationStart("listResourceObjectShadow"); try { while (true) { try { return objectRetriever.listResourceObjectShadowsAttempt(resourceOid, resourceObjectShadowType, subResult); } catch (RuntimeException ex) { attempt = logOperationAttempt(resourceOid, operation, attempt, ex, subResult); pm.registerOperationNewTrial(opHandle, attempt); } } } finally { pm.registerOperationFinish(opHandle, attempt); } } @Override public RepositoryDiag getRepositoryDiag() { LOGGER.debug("Getting repository diagnostics."); RepositoryDiag diag = new RepositoryDiag(); diag.setImplementationShortName(IMPLEMENTATION_SHORT_NAME); diag.setImplementationDescription(IMPLEMENTATION_DESCRIPTION); SqlRepositoryConfiguration config = getConfiguration(); //todo improve, find and use real values (which are used by sessionFactory) MID-1219 diag.setDriverShortName(config.getDriverClassName()); diag.setRepositoryUrl(config.getJdbcUrl()); diag.setEmbedded(config.isEmbedded()); Enumeration<Driver> drivers = DriverManager.getDrivers(); while ((drivers != null && drivers.hasMoreElements())) { Driver driver = drivers.nextElement(); if (!driver.getClass().getName().equals(config.getDriverClassName())) { continue; } diag.setDriverVersion(driver.getMajorVersion() + "." + driver.getMinorVersion()); } List<LabeledString> details = new ArrayList<>(); diag.setAdditionalDetails(details); details.add(new LabeledString(DETAILS_DATA_SOURCE, config.getDataSource())); details.add(new LabeledString(DETAILS_HIBERNATE_DIALECT, config.getHibernateDialect())); details.add(new LabeledString(DETAILS_HIBERNATE_HBM_2_DDL, config.getHibernateHbm2ddl())); readDetailsFromConnection(diag, config); Collections.sort(details, new Comparator<LabeledString>() { @Override public int compare(LabeledString o1, LabeledString o2) { return String.CASE_INSENSITIVE_ORDER.compare(o1.getLabel(), o2.getLabel()); } }); return diag; } private void readDetailsFromConnection(RepositoryDiag diag, final SqlRepositoryConfiguration config) { final List<LabeledString> details = diag.getAdditionalDetails(); Session session = getSessionFactory().openSession(); try { session.beginTransaction(); session.doWork(new Work() { @Override public void execute(Connection connection) throws SQLException { details.add(new LabeledString(DETAILS_TRANSACTION_ISOLATION, getTransactionIsolation(connection, config))); Properties info = connection.getClientInfo(); if (info == null) { return; } for (String name : info.stringPropertyNames()) { details.add(new LabeledString(DETAILS_CLIENT_INFO + name, info.getProperty(name))); } } }); session.getTransaction().commit(); if (!(getSessionFactory() instanceof SessionFactoryImpl)) { return; } SessionFactoryImpl factory = (SessionFactoryImpl) getSessionFactory(); // we try to override configuration which was read from sql repo configuration with // real configuration from session factory String dialect = factory.getDialect() != null ? factory.getDialect().getClass().getName() : null; details.add(new LabeledString(DETAILS_HIBERNATE_DIALECT, dialect)); } catch (Throwable th) { //nowhere to report error (no operation result available) session.getTransaction().rollback(); } finally { cleanupSessionAndResult(session, null); } } private String getTransactionIsolation(Connection connection, SqlRepositoryConfiguration config) { String value = config.getTransactionIsolation() != null ? config.getTransactionIsolation().name() + "(read from repo configuration)" : null; try { switch (connection.getTransactionIsolation()) { case Connection.TRANSACTION_NONE: value = "TRANSACTION_NONE (read from connection)"; break; case Connection.TRANSACTION_READ_COMMITTED: value = "TRANSACTION_READ_COMMITTED (read from connection)"; break; case Connection.TRANSACTION_READ_UNCOMMITTED: value = "TRANSACTION_READ_UNCOMMITTED (read from connection)"; break; case Connection.TRANSACTION_REPEATABLE_READ: value = "TRANSACTION_REPEATABLE_READ (read from connection)"; break; case Connection.TRANSACTION_SERIALIZABLE: value = "TRANSACTION_SERIALIZABLE (read from connection)"; break; default: value = "Unknown value in connection."; } } catch (Exception ex) { //nowhere to report error (no operation result available) } return value; } /* (non-Javadoc) * @see com.evolveum.midpoint.repo.api.RepositoryService#repositorySelfTest(com.evolveum.midpoint.schema.result.OperationResult) */ @Override public void repositorySelfTest(OperationResult parentResult) { // TODO add some SQL-specific self-test methods // No self-tests for now } @Override public void testOrgClosureConsistency(boolean repairIfNecessary, OperationResult testResult) { getClosureManager().checkAndOrRebuild(this, true, repairIfNecessary, false, false, testResult); } @Override public <T extends ObjectType> String getVersion(Class<T> type, String oid, OperationResult parentResult) throws ObjectNotFoundException, SchemaException { Validate.notNull(type, "Object type must not be null."); Validate.notNull(oid, "Object oid must not be null."); Validate.notNull(parentResult, "Operation result must not be null."); LOGGER.debug("Getting version for {} with oid '{}'.", new Object[] { type.getSimpleName(), oid }); OperationResult subResult = parentResult.createMinorSubresult(GET_VERSION); subResult.addParam("type", type.getName()); subResult.addParam("oid", oid); SqlPerformanceMonitor pm = getPerformanceMonitor(); long opHandle = pm.registerOperationStart(GET_VERSION); final String operation = "getting version"; int attempt = 1; try { while (true) { try { return objectRetriever.getVersionAttempt(type, oid, subResult); } catch (RuntimeException ex) { attempt = logOperationAttempt(null, operation, attempt, ex, subResult); pm.registerOperationNewTrial(opHandle, attempt); } } } finally { pm.registerOperationFinish(opHandle, attempt); } } @Override public <T extends ObjectType> SearchResultMetadata searchObjectsIterative(Class<T> type, ObjectQuery query, ResultHandler<T> handler, Collection<SelectorOptions<GetOperationOptions>> options, boolean strictlySequential, OperationResult result) throws SchemaException { Validate.notNull(type, "Object type must not be null."); Validate.notNull(handler, "Result handler must not be null."); Validate.notNull(result, "Operation result must not be null."); logSearchInputParameters(type, query, true, strictlySequential); OperationResult subResult = result.createSubresult(SEARCH_OBJECTS_ITERATIVE); subResult.addParam("type", type.getName()); subResult.addParam("query", query); if (query != null) { ObjectFilter filter = query.getFilter(); filter = ObjectQueryUtil.simplify(filter); if (filter instanceof NoneFilter) { subResult.recordSuccess(); return null; //shouldn't be this in ObjectQueryUtil.simplify? } else if (filter instanceof AllFilter) { query = query.cloneEmpty(); query.setFilter(null); } else { query = query.cloneEmpty(); query.setFilter(filter); } } if (getConfiguration().isIterativeSearchByPaging()) { if (strictlySequential) { objectRetriever.searchObjectsIterativeByPagingStrictlySequential(type, query, handler, options, subResult); } else { objectRetriever.searchObjectsIterativeByPaging(type, query, handler, options, subResult); } return null; } // turned off until resolved 'unfinished operation' warning // SqlPerformanceMonitor pm = getPerformanceMonitor(); // long opHandle = pm.registerOperationStart(SEARCH_OBJECTS_ITERATIVE); final String operation = "searching iterative"; int attempt = 1; try { while (true) { try { objectRetriever.searchObjectsIterativeAttempt(type, query, handler, options, subResult); return null; } catch (RuntimeException ex) { attempt = logOperationAttempt(null, operation, attempt, ex, subResult); // pm.registerOperationNewTrial(opHandle, attempt); } } } finally { // pm.registerOperationFinish(opHandle, attempt); } } @Override public boolean isAnySubordinate(String upperOrgOid, Collection<String> lowerObjectOids) throws SchemaException { Validate.notNull(upperOrgOid, "upperOrgOid must not be null."); Validate.notNull(lowerObjectOids, "lowerObjectOids must not be null."); if (LOGGER.isTraceEnabled()) LOGGER.trace("Querying for subordination upper {}, lower {}", new Object[] { upperOrgOid, lowerObjectOids }); if (lowerObjectOids.isEmpty()) { // trivial case return false; } int attempt = 1; SqlPerformanceMonitor pm = getPerformanceMonitor(); long opHandle = pm.registerOperationStart("matchObject"); try { while (true) { try { return objectRetriever.isAnySubordinateAttempt(upperOrgOid, lowerObjectOids); } catch (RuntimeException ex) { attempt = logOperationAttempt(upperOrgOid, "isAnySubordinate", attempt, ex, null); pm.registerOperationNewTrial(opHandle, attempt); } } } finally { pm.registerOperationFinish(opHandle, attempt); } } @Override public long advanceSequence(String oid, OperationResult parentResult) throws ObjectNotFoundException, SchemaException { Validate.notEmpty(oid, "Oid must not null or empty."); Validate.notNull(parentResult, "Operation result must not be null."); OperationResult result = parentResult.createSubresult(ADVANCE_SEQUENCE); result.addParam("oid", oid); if (LOGGER.isTraceEnabled()) LOGGER.trace("Advancing sequence {}", oid); int attempt = 1; SqlPerformanceMonitor pm = getPerformanceMonitor(); long opHandle = pm.registerOperationStart("advanceSequence"); try { while (true) { try { return sequenceHelper.advanceSequenceAttempt(oid, result); } catch (RuntimeException ex) { attempt = logOperationAttempt(oid, "advanceSequence", attempt, ex, null); pm.registerOperationNewTrial(opHandle, attempt); } } } finally { pm.registerOperationFinish(opHandle, attempt); } } @Override public void returnUnusedValuesToSequence(String oid, Collection<Long> unusedValues, OperationResult parentResult) throws ObjectNotFoundException, SchemaException { Validate.notEmpty(oid, "Oid must not null or empty."); Validate.notNull(parentResult, "Operation result must not be null."); OperationResult result = parentResult.createSubresult(RETURN_UNUSED_VALUES_TO_SEQUENCE); result.addParam("oid", oid); if (LOGGER.isTraceEnabled()) { LOGGER.trace("Returning unused values of {} to sequence {}", unusedValues, oid); } if (unusedValues == null || unusedValues.isEmpty()) { result.recordSuccess(); return; } int attempt = 1; SqlPerformanceMonitor pm = getPerformanceMonitor(); long opHandle = pm.registerOperationStart("returnUnusedValuesToSequence"); try { while (true) { try { sequenceHelper.returnUnusedValuesToSequenceAttempt(oid, unusedValues, result); return; } catch (RuntimeException ex) { attempt = logOperationAttempt(oid, "returnUnusedValuesToSequence", attempt, ex, null); pm.registerOperationNewTrial(opHandle, attempt); } } } finally { pm.registerOperationFinish(opHandle, attempt); } } @Override public String executeArbitraryQuery(String query, OperationResult result) { Validate.notEmpty(query, "Query must not be empty."); Validate.notNull(result, "Operation result must not be null."); LOGGER.debug("Executing arbitrary query '{}'.", query); final String operation = "querying"; int attempt = 1; OperationResult subResult = result.createMinorSubresult(EXECUTE_ARBITRARY_QUERY); subResult.addParam("query", query); SqlPerformanceMonitor pm = getPerformanceMonitor(); long opHandle = pm.registerOperationStart("executeArbitraryQuery"); try { while (true) { try { return objectRetriever.executeArbitraryQueryAttempt(query, subResult); } catch (RuntimeException ex) { attempt = logOperationAttempt(null, operation, attempt, ex, subResult); pm.registerOperationNewTrial(opHandle, attempt); } } } finally { pm.registerOperationFinish(opHandle, attempt); } } }