OrientDBRepoService.java revision 5c625c17767aae6167c744e9e1ad40c3d1455e31
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2011-2013 ForgeRock AS. All Rights Reserved
*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*/
/**
* Repository service implementation using OrientDB
* @author aegloff
*/
@Component(name = OrientDBRepoService.PID, immediate=true, policy=ConfigurationPolicy.REQUIRE, enabled=true)
@Service (value = {RepositoryService.class, RequestHandler.class}) // Omit the RepoBootService interface from the managed service
@Properties({
// Keys in the JSON configuration
int poolMinSize = 5;
int poolMaxSize = 20;
// Current configuration
// TODO: evaluate use of Guice instead
try {
}
}
try {
}
}
try {
}
}
try {
}
}
final QueryResultHandler handler) {
try {
}
}
/**
* <p>
* The object will contain metadata properties, including object identifier
* {@code _id}, and object version {@code _rev} to enable optimistic
* concurrency supported by OrientDB and OpenIDM.
*
* @param request
* the identifier of the object to retrieve from the object set.
* @throws NotFoundException
* if the specified object could not be found.
* @throws ForbiddenException
* if access to the object is forbidden.
* @throws BadRequestException
* if the passed identifier is invalid
* @return the requested object.
*/
//@Override
throw new NotFoundException("The repository requires clients to supply an identifier for the object to create. Full identifier: " + fullId + " local identifier: " + localId);
throw new NotFoundException("The object identifier did not include sufficient information to determine the object type: " + fullId);
}
try {
}
} finally {
}
}
}
/**
* 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 context
* the client-generated identifier to use, or {@code null} if
* server-generated identifier is requested.
* @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
// Used currently for logging
throw new NotFoundException("The repository requires clients to supply an identifier for the object to create. Full identifier: " + fullId + " local identifier: " + localId);
throw new NotFoundException("The object identifier did not include sufficient information to determine the object type: " + fullId);
}
try{
// Rather than using MVCC for insert, rely on primary key uniqueness constraints to detect duplicate create
} 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);
// Because the OpenIDM ID is defined as unique, duplicate inserts must fail.
// OrientDB may wrap the IndexException root cause.
throw new PreconditionFailedException("Create rejected as Object with same ID already exists and was detected. "
} else {
throw ex;
}
} catch (RuntimeException e){
throw e;
} finally {
}
}
}
/**
* Updates the specified object in the object set.
* <p>
* This implementation requires MVCC and hence enforces that clients state what revision they expect
* to be updating
*
* If successful, this method updates metadata properties within the passed object,
* including: a new {@code _rev} value for the revised object's version
*
* @param fullId the identifier of the object to be put, or {@code null} to request a generated identifier.
* @param rev the version of the object to update; or {@code null} if not provided.
* @param obj the contents of the object to put in the object set.
* @throws ConflictException if version is required but is {@code null}.
* @throws ForbiddenException if access to the object is forbidden.
* @throws NotFoundException if the specified object could not be found.
* @throws PreconditionFailedException if version did not match the existing object in the set.
* @throws BadRequestException if the passed identifier is invalid
*/
//@Override
throw new ConflictException("Object passed into update does not have revision it expects set.");
} else {
}
try{
if (existingDoc == null) {
}
updatedDoc.save();
// Set ID to return to caller
} catch (OConcurrentModificationException ex) {
throw new PreconditionFailedException("Update rejected as current Object revision is different than expected by caller, the object has changed since retrieval: " + ex.getMessage(), ex);
} catch (RuntimeException e){
throw e;
} finally {
}
}
}
/**
* Deletes the specified object from the object set.
*
* {@inheritDoc}
*
* @throws NotFoundException
* if the specified object could not be found.
* @throws ForbiddenException
* if access to the object is forbidden.
* @throws ConflictException
* if version is required but is {@code null}.
* @throws PreconditionFailedException
* if version did not match the existing object in the set.
*/
//@Override
throw new ConflictException("Object passed into delete does not have revision it expects set.");
}
try {
if (existingDoc == null) {
}
} catch (OConcurrentModificationException ex) {
throw new PreconditionFailedException("Delete rejected as current Object revision is different than expected by caller, the object has changed since retrieval.", ex);
} catch (RuntimeException e){
throw e;
} finally {
}
}
}
// TODO: impl
}
}
/**
* Performs the query on the specified object and returns the associated results.
* <p>
* Queries are parametric; a set of named parameters is provided as the query criteria.
* The query result is a JSON object structure composed of basic Java types.
*
* The returned map is structured as follow:
* - The top level map contains meta-data about the query, plus an entry with the actual result records.
* - The <code>QueryConstants</code> defines the map keys, including the result records (QUERY_RESULT)
*
* @param context
* identifies the object to query.
* @param request
* the parameters of the query to perform.
* @return the query results, which includes meta-data and the result
* records in JSON object structure format.
* @throws NotFoundException
* if the specified object could not be found.
* @throws BadRequestException
* if the specified params contain invalid arguments, e.g. a
* query id that is not configured, a query expression that is
* invalid, or missing query substitution tokens.
* @throws ForbiddenException
* if access to the object or specified query is forbidden.
*/
//@Override
// TODO: replace with common utility
// Whilst the URI starts with a slash, but consider relative URI
}
// TODO: Statistics is not returned in result anymore
// TODO: result is not needed in map form anymore
try {
//List<Map<String, Object>> docs = new ArrayList<Map<String, Object>>();
//result.put(QueryConstants.QUERY_RESULT, docs);
if (queryResult != null) {
//docs.add(convertedEntry);
new JsonValue(convertedEntry)));
}
}
if (logger.isDebugEnabled()) {
}
} finally {
}
}
}
/**
* @return A connection from the pool. Call close on the connection when done to return to the pool.
* @throws org.forgerock.openidm.objset.InternalServerErrorException
*/
int retryCount = 0;
retryCount++;
try {
if (retryCount > 1) {
}
// TODO: remove work-around once OrientDB resolves this condition
if (retryCount == maxRetry) {
logger.warn("Failure reported acquiring connection from pool, retried {} times before giving up.", retryCount, ex);
throw new InternalServerErrorException(
"Failure reported acquiring connection from pool, retried " + retryCount + " times before giving up: "
} else {
try {
} catch (InterruptedException iex) {
// ignore that sleep was interrupted
}
}
}
}
return db;
}
// TODO: replace with common utility to handle ID, this is temporary
if (lastSlashPos > -1) {
}
return localId;
}
int startPos = 0;
// This should not be necessary as relative URI should not start with slash
startPos = 1;
}
return type;
}
// TODO: replace with common utility to handle ID, this is temporary
if (lastSlashPos > -1) {
int startPos = 0;
// This should not be necessary as relative URI should not start with slash
startPos = 1;
}
}
return type;
}
}
//public static String idToOrientClassName(String id) {
// String type = getObjectType(id);
// return typeToOrientClassName(type);
//}
/**
* Detect if the root cause of the exception is an index constraint violation
* This is necessary as the database may wrap this root cause in further exceptions,
* masking the underlying cause
* @param ex The throwable to check
* @param maxLevels the maximum level of causes to check, avoiding the cost
* of checking recursiveness
* @return
*/
if (maxLevels > 0) {
}
}
return false;
}
/**
* Populate and return a repository service that knows how to query and manipulate configuration.
*
* @param repoConfig the bootstrap configuration
* @return the boot repository service. This instance is not managed by SCR and needs to be manually registered.
*/
return bootRepo;
}
try {
} catch (RuntimeException ex) {
throw ex;
}
embeddedServer = new EmbeddedOServerService();
}
/**
* Initialize the instnace with the given configuration.
*
* (bootstrap) instances.
*
* @param config the configuration
*/
try {
} catch (RuntimeException ex) {
throw ex;
}
try {
} catch (RuntimeException ex) {
throw ex;
}
}
return config.get(OrientDBRepoService.CONFIG_DB_URL).defaultTo("local:" + orientDbFolder).asString();
}
}
}
/**
* Adapts a {@code Throwable} to a {@code ResourceException}. If the
* {@code Throwable} is an JSON {@code JsonValueException} then an
* appropriate {@code ResourceException} is returned, otherwise an
* {@code InternalServerErrorException} is returned.
*
* @param t
* The {@code Throwable} to be converted.
* @return The equivalent resource exception.
*/
int resourceResultCode;
try {
throw t;
} catch (OConcurrentModificationException ex) {
} catch (final ResourceException e) {
return e;
} catch (final JsonValueException e) {
}
}
/**
* Handle an existing activated service getting changed;
* e.g. configuration changes or dependency changes
*
* @param compContext THe OSGI component context
* @throws Exception if handling the modified event failed
*/
try {
} catch (RuntimeException ex) {
logger.warn("Configuration invalid and could not be parsed, can not start OrientDB repository", ex);
throw ex;
}
if (existingConfig != null
// If the DB pool settings don't change keep the existing pool
} else {
// If the DB pool settings changed do a more complete re-initialization
logger.info("Re-initialize repository with latest configuration - including DB pool setting changes.");
}
}
cleanup();
if (embeddedServer != null) {
}
}
/**
* Cleanup and close the repository
*/
void cleanup() {
}
}