/** * Creates a new object in the object set. * * <p>This method sets the {@code _id} property to the assigned identifier for the object, and the * {@code _rev} property to the revised object version (For optimistic concurrency) * * @param request the contents of the object to create in the object set. * @throws NotFoundException if the specified id could not be resolved. * @throws ForbiddenException if access to the object or object set is forbidden. * @throws ConflictException if an object with the same ID already exists. */ @Override public ResourceResponse create(CreateRequest request) throws ResourceException { if (request.getResourcePathObject().isEmpty()) { throw new NotFoundException( "The object identifier did not include sufficient information to determine the object type: " + request.getResourcePath()); } final String type = request.getResourcePath(); // TODO: should CREST support server side generation of ID itself? final String localId = (request.getNewResourceId() == null || "".equals(request.getNewResourceId())) ? UUID.randomUUID().toString() // Generate ID server side. : request.getNewResourceId(); // Used currently for logging String fullId = request.getResourcePathObject().child(localId).toString(); String orientClassName = typeToOrientClassName(type); JsonValue obj = request.getContent(); obj.put(DocumentUtil.TAG_ID, localId); ODatabaseDocumentTx db = getConnection(); try { // Rather than using MVCC for insert, rely on primary key uniqueness constraints to detect // duplicate create ODocument newDoc = DocumentUtil.toDocument(obj, null, db, orientClassName); logger.trace("Created doc for id: {} to save {}", fullId, newDoc); newDoc.save(); obj.put(DocumentUtil.TAG_REV, Integer.toString(newDoc.getVersion())); logger.debug("Completed create for id: {} revision: {}", fullId, newDoc.getVersion()); logger.trace("Create payload for id: {} doc: {}", fullId, newDoc); return newResourceResponse( obj.get(DocumentUtil.TAG_ID).asString(), obj.get(DocumentUtil.TAG_REV).asString(), obj); } catch (ORecordDuplicatedException ex) { // Because the OpenIDM ID is defined as unique, duplicate inserts must fail throw new PreconditionFailedException( "Create rejected as Object with same ID already exists. " + ex.getMessage(), ex); } catch (OIndexException ex) { // Because the OpenIDM ID is defined as unique, duplicate inserts must fail throw new PreconditionFailedException( "Create rejected as Object with same ID already exists. " + ex.getMessage(), ex); } catch (ODatabaseException ex) { // Because the OpenIDM ID is defined as unique, duplicate inserts must fail. // OrientDB may wrap the IndexException root cause. if (isCauseIndexException(ex, 10) || isCauseRecordDuplicatedException(ex, 10)) { throw new PreconditionFailedException( "Create rejected as Object with same ID already exists and was detected. " + ex.getMessage(), ex); } else { throw ex; } } catch (RuntimeException e) { throw e; } finally { if (db != null) { db.close(); } } }