Search in sources :

Example 6 with RObject

use of com.evolveum.midpoint.repo.sql.data.common.RObject in project midpoint by Evolveum.

the class ObjectUpdater method modifyObjectAttempt.

public <T extends ObjectType> void modifyObjectAttempt(Class<T> type, String oid, Collection<? extends ItemDelta> modifications, RepoModifyOptions modifyOptions, OperationResult result) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException, SerializationRelatedException {
    // clone - because some certification and lookup table related methods manipulate this collection and even their constituent deltas
    // TODO clone elements only if necessary
    modifications = CloneUtil.cloneCollectionMembers(modifications);
    //modifications = new ArrayList<>(modifications);
    LOGGER.debug("Modifying object '{}' with oid '{}'.", new Object[] { type.getSimpleName(), oid });
    LOGGER_PERFORMANCE.debug("> modify object {}, oid={}, modifications={}", type.getSimpleName(), oid, modifications);
    if (LOGGER.isTraceEnabled()) {
        LOGGER.trace("Modifications:\n{}", DebugUtil.debugDump(modifications));
    }
    Session session = null;
    OrgClosureManager.Context closureContext = null;
    try {
        session = baseHelper.beginTransaction();
        closureContext = closureManager.onBeginTransactionModify(session, type, oid, modifications);
        Collection<? extends ItemDelta> lookupTableModifications = lookupTableHelper.filterLookupTableModifications(type, modifications);
        Collection<? extends ItemDelta> campaignCaseModifications = caseHelper.filterCampaignCaseModifications(type, modifications);
        if (!modifications.isEmpty() || RepoModifyOptions.isExecuteIfNoChanges(modifyOptions)) {
            // JpegPhoto (RFocusPhoto) is a special kind of entity. First of all, it is lazily loaded, because photos are really big.
            // Each RFocusPhoto naturally belongs to one RFocus, so it would be appropriate to set orphanRemoval=true for focus-photo
            // association. However, this leads to a strange problem when merging in-memory RFocus object with the database state:
            // If in-memory RFocus object has no photo associated (because of lazy loading), then the associated RFocusPhoto is deleted.
            //
            // To prevent this behavior, we've set orphanRemoval to false. Fortunately, the remove operation on RFocus
            // seems to be still cascaded to RFocusPhoto. What we have to implement ourselves, however, is removal of RFocusPhoto
            // _without_ removing of RFocus. In order to know whether the photo has to be removed, we have to retrieve
            // its value, apply the delta (e.g. if the delta is a DELETE VALUE X, we have to know whether X matches current
            // value of the photo), and if the resulting value is empty, we have to manually delete the RFocusPhoto instance.
            //
            // So the first step is to retrieve the current value of photo - we obviously do this only if the modifications
            // deal with the jpegPhoto property.
            Collection<SelectorOptions<GetOperationOptions>> options;
            boolean containsFocusPhotoModification = FocusType.class.isAssignableFrom(type) && containsPhotoModification(modifications);
            if (containsFocusPhotoModification) {
                options = Collections.singletonList(SelectorOptions.create(FocusType.F_JPEG_PHOTO, GetOperationOptions.createRetrieve(RetrieveOption.INCLUDE)));
            } else {
                options = null;
            }
            // get object
            PrismObject<T> prismObject = objectRetriever.getObjectInternal(session, type, oid, options, true, result);
            // apply diff
            LOGGER.trace("OBJECT before:\n{}", prismObject.debugDumpLazily());
            PrismObject<T> originalObject = null;
            if (closureManager.isEnabled()) {
                originalObject = prismObject.clone();
            }
            ItemDelta.applyTo(modifications, prismObject);
            LOGGER.trace("OBJECT after:\n{}", prismObject.debugDumpLazily());
            // Continuing the photo treatment: should we remove the (now obsolete) focus photo?
            // We have to test prismObject at this place, because updateFullObject (below) removes photo property from the prismObject.
            boolean shouldPhotoBeRemoved = containsFocusPhotoModification && ((FocusType) prismObject.asObjectable()).getJpegPhoto() == null;
            // merge and update object
            LOGGER.trace("Translating JAXB to data type.");
            ObjectTypeUtil.normalizeAllRelations(prismObject);
            RObject rObject = createDataObjectFromJAXB(prismObject, PrismIdentifierGenerator.Operation.MODIFY);
            rObject.setVersion(rObject.getVersion() + 1);
            updateFullObject(rObject, prismObject);
            LOGGER.trace("Starting merge.");
            session.merge(rObject);
            if (closureManager.isEnabled()) {
                closureManager.updateOrgClosure(originalObject, modifications, session, oid, type, OrgClosureManager.Operation.MODIFY, closureContext);
            }
            // we have to remove the photo manually.
            if (shouldPhotoBeRemoved) {
                Query query = session.createQuery("delete RFocusPhoto where ownerOid = :oid");
                query.setParameter("oid", prismObject.getOid());
                query.executeUpdate();
                LOGGER.trace("Focus photo for {} was deleted", prismObject.getOid());
            }
        }
        if (LookupTableType.class.isAssignableFrom(type)) {
            lookupTableHelper.updateLookupTableData(session, oid, lookupTableModifications);
        }
        if (AccessCertificationCampaignType.class.isAssignableFrom(type)) {
            caseHelper.updateCampaignCases(session, oid, campaignCaseModifications, modifyOptions);
        }
        LOGGER.trace("Before commit...");
        session.getTransaction().commit();
        LOGGER.trace("Committed!");
    } catch (ObjectNotFoundException ex) {
        baseHelper.rollbackTransaction(session, ex, result, true);
        throw ex;
    } catch (ConstraintViolationException ex) {
        handleConstraintViolationException(session, ex, result);
        baseHelper.rollbackTransaction(session, ex, result, true);
        LOGGER.debug("Constraint violation occurred (will be rethrown as ObjectAlreadyExistsException).", ex);
        //todo improve (we support only 5 DB, so we should probably do some hacking in here)
        throw new ObjectAlreadyExistsException(ex);
    } catch (SchemaException ex) {
        baseHelper.rollbackTransaction(session, ex, result, true);
        throw ex;
    } catch (DtoTranslationException | RuntimeException ex) {
        baseHelper.handleGeneralException(ex, session, result);
    } finally {
        cleanupClosureAndSessionAndResult(closureContext, session, result);
        LOGGER.trace("Session cleaned up.");
    }
}
Also used : SchemaException(com.evolveum.midpoint.util.exception.SchemaException) SQLQuery(org.hibernate.SQLQuery) Query(org.hibernate.Query) DtoTranslationException(com.evolveum.midpoint.repo.sql.util.DtoTranslationException) SelectorOptions(com.evolveum.midpoint.schema.SelectorOptions) RObject(com.evolveum.midpoint.repo.sql.data.common.RObject) FocusType(com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType) ObjectNotFoundException(com.evolveum.midpoint.util.exception.ObjectNotFoundException) ConstraintViolationException(org.hibernate.exception.ConstraintViolationException) ObjectAlreadyExistsException(com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException) Session(org.hibernate.Session)

Example 7 with RObject

use of com.evolveum.midpoint.repo.sql.data.common.RObject in project midpoint by Evolveum.

the class MetadataFactory method toJAXB.

public static MetadataType toJAXB(Metadata repo, PrismContext context) {
    if (isNull(repo)) {
        return null;
    }
    MetadataType jaxb = new MetadataType();
    jaxb.setCreateChannel(repo.getCreateChannel());
    jaxb.setCreateTimestamp(repo.getCreateTimestamp());
    jaxb.setModifyChannel(repo.getModifyChannel());
    jaxb.setModifyTimestamp(repo.getModifyTimestamp());
    if (repo.getCreatorRef() != null) {
        jaxb.setCreatorRef(repo.getCreatorRef().toJAXB(context));
    }
    if (repo.getModifierRef() != null) {
        jaxb.setModifierRef(repo.getModifierRef().toJAXB(context));
    }
    if (repo instanceof RObject) {
        List refs = RUtil.safeSetReferencesToList(repo.getCreateApproverRef(), context);
        if (!refs.isEmpty()) {
            jaxb.getCreateApproverRef().addAll(refs);
        }
        refs = RUtil.safeSetReferencesToList(repo.getModifyApproverRef(), context);
        if (!refs.isEmpty()) {
            jaxb.getModifyApproverRef().addAll(refs);
        }
    } else {
    }
    return jaxb;
}
Also used : RObject(com.evolveum.midpoint.repo.sql.data.common.RObject) MetadataType(com.evolveum.midpoint.xml.ns._public.common.common_3.MetadataType) List(java.util.List)

Example 8 with RObject

use of com.evolveum.midpoint.repo.sql.data.common.RObject in project midpoint by Evolveum.

the class ObjectRetriever method getObjectInternal.

public <T extends ObjectType> PrismObject<T> getObjectInternal(Session session, Class<T> type, String oid, Collection<SelectorOptions<GetOperationOptions>> options, boolean lockForUpdate, OperationResult operationResult) throws ObjectNotFoundException, SchemaException, DtoTranslationException {
    boolean lockedForUpdateViaHibernate = false;
    boolean lockedForUpdateViaSql = false;
    LockOptions lockOptions = new LockOptions();
    //todo fix lock for update!!!!!
    if (lockForUpdate) {
        if (getConfiguration().isLockForUpdateViaHibernate()) {
            lockOptions.setLockMode(LockMode.PESSIMISTIC_WRITE);
            lockedForUpdateViaHibernate = true;
        } else if (getConfiguration().isLockForUpdateViaSql()) {
            LOGGER.trace("Trying to lock object {} for update (via SQL)", oid);
            long time = System.currentTimeMillis();
            SQLQuery q = session.createSQLQuery("select oid from m_object where oid = ? for update");
            q.setString(0, oid);
            Object result = q.uniqueResult();
            if (result == null) {
                return throwObjectNotFoundException(type, oid);
            }
            if (LOGGER.isTraceEnabled()) {
                LOGGER.trace("Locked via SQL (in {} ms)", System.currentTimeMillis() - time);
            }
            lockedForUpdateViaSql = true;
        }
    }
    if (LOGGER.isTraceEnabled()) {
        if (lockedForUpdateViaHibernate) {
            LOGGER.trace("Getting object {} with locking for update (via hibernate)", oid);
        } else if (lockedForUpdateViaSql) {
            LOGGER.trace("Getting object {}, already locked for update (via SQL)", oid);
        } else {
            LOGGER.trace("Getting object {} without locking for update", oid);
        }
    }
    GetObjectResult fullObject = null;
    if (!lockForUpdate) {
        Query query = session.getNamedQuery("get.object");
        query.setString("oid", oid);
        query.setResultTransformer(GetObjectResult.RESULT_STYLE.getResultTransformer());
        query.setLockOptions(lockOptions);
        fullObject = (GetObjectResult) query.uniqueResult();
    } else {
        // we're doing update after this get, therefore we load full object right now
        // (it would be loaded during merge anyway)
        // this just loads object to hibernate session, probably will be removed later. Merge after this get
        // will be faster. Read and use object only from fullObject column.
        // todo remove this later [lazyman]
        Criteria criteria = session.createCriteria(ClassMapper.getHQLTypeClass(type));
        criteria.add(Restrictions.eq("oid", oid));
        criteria.setLockMode(lockOptions.getLockMode());
        RObject obj = (RObject) criteria.uniqueResult();
        if (obj != null) {
            fullObject = new GetObjectResult(obj.getOid(), obj.getFullObject(), obj.getStringsCount(), obj.getLongsCount(), obj.getDatesCount(), obj.getReferencesCount(), obj.getPolysCount(), obj.getBooleansCount());
        }
    }
    LOGGER.trace("Got it.");
    if (fullObject == null) {
        throwObjectNotFoundException(type, oid);
    }
    LOGGER.trace("Transforming data to JAXB type.");
    PrismObject<T> prismObject = updateLoadedObject(fullObject, type, oid, options, null, session, operationResult);
    validateObjectType(prismObject, type);
    return prismObject;
}
Also used : ObjectQuery(com.evolveum.midpoint.prism.query.ObjectQuery) RQuery(com.evolveum.midpoint.repo.sql.query.RQuery) RObject(com.evolveum.midpoint.repo.sql.data.common.RObject) RObject(com.evolveum.midpoint.repo.sql.data.common.RObject)

Example 9 with RObject

use of com.evolveum.midpoint.repo.sql.data.common.RObject in project midpoint by Evolveum.

the class ObjectUpdater method overwriteAddObjectAttempt.

private <T extends ObjectType> String overwriteAddObjectAttempt(PrismObject<T> object, RObject rObject, String originalOid, Session session, OrgClosureManager.Context closureContext, OperationResult result) throws ObjectAlreadyExistsException, SchemaException, DtoTranslationException {
    PrismObject<T> oldObject = null;
    //check if object already exists, find differences and increment version if necessary
    Collection<? extends ItemDelta> modifications = null;
    if (originalOid != null) {
        try {
            oldObject = objectRetriever.getObjectInternal(session, object.getCompileTimeClass(), originalOid, null, true, result);
            ObjectDelta<T> delta = object.diff(oldObject);
            modifications = delta.getModifications();
            LOGGER.trace("overwriteAddObjectAttempt: originalOid={}, modifications={}", originalOid, modifications);
            //we found existing object which will be overwritten, therefore we increment version
            Integer version = RUtil.getIntegerFromString(oldObject.getVersion());
            version = (version == null) ? 0 : ++version;
            rObject.setVersion(version);
        //            } catch (QueryException ex) {
        //                baseHelper.handleGeneralCheckedException(ex, session, null);
        } catch (ObjectNotFoundException ex) {
        //it's ok that object was not found, therefore we won't be overwriting it
        }
    }
    updateFullObject(rObject, object);
    RObject merged = (RObject) session.merge(rObject);
    lookupTableHelper.addLookupTableRows(session, rObject, oldObject != null);
    caseHelper.addCertificationCampaignCases(session, rObject, oldObject != null);
    if (closureManager.isEnabled()) {
        OrgClosureManager.Operation operation;
        if (modifications == null) {
            operation = OrgClosureManager.Operation.ADD;
            modifications = createAddParentRefDelta(object);
        } else {
            operation = OrgClosureManager.Operation.MODIFY;
        }
        closureManager.updateOrgClosure(oldObject, modifications, session, merged.getOid(), object.getCompileTimeClass(), operation, closureContext);
    }
    return merged.getOid();
}
Also used : RObject(com.evolveum.midpoint.repo.sql.data.common.RObject) ObjectNotFoundException(com.evolveum.midpoint.util.exception.ObjectNotFoundException)

Example 10 with RObject

use of com.evolveum.midpoint.repo.sql.data.common.RObject in project midpoint by Evolveum.

the class ObjectUpdater method addObjectAttempt.

public <T extends ObjectType> String addObjectAttempt(PrismObject<T> object, RepoAddOptions options, OperationResult result) throws ObjectAlreadyExistsException, SchemaException {
    LOGGER_PERFORMANCE.debug("> add object {}, oid={}, overwrite={}", object.getCompileTimeClass().getSimpleName(), object.getOid(), options.isOverwrite());
    String oid = null;
    Session session = null;
    OrgClosureManager.Context closureContext = null;
    // it is needed to keep the original oid for example for import options. if we do not keep it
    // and it was null it can bring some error because the oid is set when the object contains orgRef
    // or it is org. and by the import we do not know it so it will be trying to delete non-existing object
    String originalOid = object.getOid();
    try {
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("Object\n{}", object.debugDump());
        }
        ObjectTypeUtil.normalizeAllRelations(object);
        LOGGER.trace("Translating JAXB to data type.");
        PrismIdentifierGenerator.Operation operation = options.isOverwrite() ? PrismIdentifierGenerator.Operation.ADD_WITH_OVERWRITE : PrismIdentifierGenerator.Operation.ADD;
        RObject rObject = createDataObjectFromJAXB(object, operation);
        session = baseHelper.beginTransaction();
        closureContext = closureManager.onBeginTransactionAdd(session, object, options.isOverwrite());
        if (options.isOverwrite()) {
            oid = overwriteAddObjectAttempt(object, rObject, originalOid, session, closureContext, result);
        } else {
            oid = nonOverwriteAddObjectAttempt(object, rObject, originalOid, session, closureContext);
        }
        session.getTransaction().commit();
        LOGGER.trace("Saved object '{}' with oid '{}'", object.getCompileTimeClass().getSimpleName(), oid);
        object.setOid(oid);
    } catch (ConstraintViolationException ex) {
        handleConstraintViolationException(session, ex, result);
        baseHelper.rollbackTransaction(session, ex, result, true);
        LOGGER.debug("Constraint violation occurred (will be rethrown as ObjectAlreadyExistsException).", ex);
        // to the original oid and prevent of unexpected behaviour (e.g. by import with overwrite option)
        if (StringUtils.isEmpty(originalOid)) {
            object.setOid(null);
        }
        String constraintName = ex.getConstraintName();
        // Breaker to avoid long unreadable messages
        if (constraintName != null && constraintName.length() > SqlRepositoryServiceImpl.MAX_CONSTRAINT_NAME_LENGTH) {
            constraintName = null;
        }
        throw new ObjectAlreadyExistsException("Conflicting object already exists" + (constraintName == null ? "" : " (violated constraint '" + constraintName + "')"), ex);
    } catch (ObjectAlreadyExistsException | SchemaException ex) {
        baseHelper.rollbackTransaction(session, ex, result, true);
        throw ex;
    } catch (DtoTranslationException | RuntimeException ex) {
        baseHelper.handleGeneralException(ex, session, result);
    } finally {
        cleanupClosureAndSessionAndResult(closureContext, session, result);
    }
    return oid;
}
Also used : SchemaException(com.evolveum.midpoint.util.exception.SchemaException) PrismIdentifierGenerator(com.evolveum.midpoint.repo.sql.util.PrismIdentifierGenerator) DtoTranslationException(com.evolveum.midpoint.repo.sql.util.DtoTranslationException) RObject(com.evolveum.midpoint.repo.sql.data.common.RObject) ConstraintViolationException(org.hibernate.exception.ConstraintViolationException) ObjectAlreadyExistsException(com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException) Session(org.hibernate.Session)

Aggregations

RObject (com.evolveum.midpoint.repo.sql.data.common.RObject)10 ObjectNotFoundException (com.evolveum.midpoint.util.exception.ObjectNotFoundException)6 DtoTranslationException (com.evolveum.midpoint.repo.sql.util.DtoTranslationException)5 SchemaException (com.evolveum.midpoint.util.exception.SchemaException)5 Session (org.hibernate.Session)5 ObjectAlreadyExistsException (com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException)3 ConstraintViolationException (org.hibernate.exception.ConstraintViolationException)3 PrismIdentifierGenerator (com.evolveum.midpoint.repo.sql.util.PrismIdentifierGenerator)2 SystemException (com.evolveum.midpoint.util.exception.SystemException)2 SequenceType (com.evolveum.midpoint.xml.ns._public.common.common_3.SequenceType)2 IdentifierPathSegment (com.evolveum.midpoint.prism.path.IdentifierPathSegment)1 ItemPath (com.evolveum.midpoint.prism.path.ItemPath)1 ParentPathSegment (com.evolveum.midpoint.prism.path.ParentPathSegment)1 ObjectQuery (com.evolveum.midpoint.prism.query.ObjectQuery)1 SerializationRelatedException (com.evolveum.midpoint.repo.sql.SerializationRelatedException)1 RepositoryContext (com.evolveum.midpoint.repo.sql.data.RepositoryContext)1 ObjectReference (com.evolveum.midpoint.repo.sql.data.common.ObjectReference)1 RPolyString (com.evolveum.midpoint.repo.sql.data.common.embedded.RPolyString)1 RQuery (com.evolveum.midpoint.repo.sql.query.RQuery)1 IdGeneratorResult (com.evolveum.midpoint.repo.sql.util.IdGeneratorResult)1