/**
* Licensed to the Austrian Association for Software Tool Integration (AASTI)
* under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. The AASTI licenses this file to you 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.openengsb.core.edb.jpa.internal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.openengsb.core.api.context.ContextHolder;
import org.openengsb.core.api.model.CommitMetaInfo;
import org.openengsb.core.api.model.CommitQueryRequest;
import org.openengsb.core.api.model.QueryRequest;
import org.openengsb.core.api.security.AuthenticationContext;
import org.openengsb.core.edb.api.EDBCommit;
import org.openengsb.core.edb.api.EDBException;
import org.openengsb.core.edb.api.EDBLogEntry;
import org.openengsb.core.edb.api.EDBObject;
import org.openengsb.core.edb.api.hooks.EDBBeginCommitHook;
import org.openengsb.core.edb.api.hooks.EDBErrorHook;
import org.openengsb.core.edb.api.hooks.EDBPostCommitHook;
import org.openengsb.core.edb.api.hooks.EDBPreCommitHook;
import org.openengsb.core.edb.jpa.internal.dao.JPADao;
import org.openengsb.core.edb.jpa.internal.util.EDBUtils;
/**
* The implementation of the EngineeringDatabaseService, extending the AbstractEDBService
*/
public class EDBService extends AbstractEDBService {
private final JPADao dao;
private final AuthenticationContext authenticationContext;
public EDBService(JPADao dao, AuthenticationContext authenticationContext,
List<EDBBeginCommitHook> beginCommitHooks, List<EDBPreCommitHook> preCommitHooks,
List<EDBPostCommitHook> postCommitHooks, List<EDBErrorHook> errorHooks,
Boolean revisionCheckEnabled) {
super(beginCommitHooks, preCommitHooks, postCommitHooks, errorHooks, revisionCheckEnabled, EDBService.class);
this.dao = dao;
this.authenticationContext = authenticationContext;
}
@Override
public Long commit(EDBCommit commit) throws EDBException {
return performCommitLogic(commit);
}
@Override
public EDBObject getObject(String oid) throws EDBException {
getLogger().debug("loading newest JPAObject with the oid {}", oid);
JPAObject temp = dao.getJPAObject(oid);
return EDBUtils.convertJPAObjectToEDBObject(temp);
}
@Override
public EDBObject getObject(String oid, Long timestamp) throws EDBException {
getLogger().debug("loading JPAObject with the oid {} for timestamp {}", oid, timestamp);
JPAObject temp = dao.getJPAObject(oid, timestamp);
return EDBUtils.convertJPAObjectToEDBObject(temp);
}
@Override
public List<EDBObject> getObjects(List<String> oids) throws EDBException {
List<JPAObject> objects = dao.getJPAObjects(oids);
return EDBUtils.convertJPAObjectsToEDBObjects(objects);
}
@Override
public List<EDBObject> getHistory(String oid) throws EDBException {
getLogger().debug("loading history of JPAObject with the oid {}", oid);
List<JPAObject> objects = dao.getJPAObjectHistory(oid);
return EDBUtils.convertJPAObjectsToEDBObjects(objects);
}
@Override
public List<EDBObject> getHistoryForTimeRange(String oid, Long from, Long to) throws EDBException {
getLogger().debug("loading JPAObject with the oid {} from "
+ "the timestamp {} to the timestamp {}", new Object[]{ oid, from, to });
List<JPAObject> objects = dao.getJPAObjectHistory(oid, from, to);
return EDBUtils.convertJPAObjectsToEDBObjects(objects);
}
@Override
public List<EDBLogEntry> getLog(String oid, Long from, Long to) throws EDBException {
getLogger().debug("loading the log of JPAObject with the oid {} from "
+ "the timestamp {} to the timestamp {}", new Object[]{ oid, from, to });
List<EDBObject> history = getHistoryForTimeRange(oid, from, to);
List<JPACommit> commits = dao.getJPACommit(oid, from, to);
if (history.size() != commits.size()) {
throw new EDBException("inconsistent log " + Integer.toString(commits.size()) + " commits for "
+ Integer.toString(history.size()) + " history entries");
}
List<EDBLogEntry> log = new ArrayList<EDBLogEntry>();
for (int i = 0; i < history.size(); ++i) {
log.add(new LogEntry(commits.get(i), history.get(i)));
}
return log;
}
@Override
public List<EDBObject> getHead() throws EDBException {
return dao.getJPAHead(System.currentTimeMillis()).getEDBObjects();
}
@Override
public List<EDBObject> getHead(long timestamp) throws EDBException {
getLogger().debug("load the elements of the JPAHead with the timestamp {}", timestamp);
JPAHead head = dao.getJPAHead(timestamp);
if (head != null) {
return head.getEDBObjects();
}
throw new EDBException("Failed to get head for timestamp " + Long.toString(timestamp));
}
@Override
public List<EDBObject> query(QueryRequest request) throws EDBException {
getLogger().debug("Query for objects based on the request: {}", request);
try {
return EDBUtils.convertJPAObjectsToEDBObjects(dao.query(request));
} catch (Exception ex) {
throw new EDBException("Failed to query for objects with the given map", ex);
}
}
@Override
public List<EDBCommit> getCommitsByKeyValue(String key, Object value) throws EDBException {
Map<String, Object> queryMap = new HashMap<String, Object>();
queryMap.put(key, value);
return getCommits(queryMap);
}
@Override
public List<EDBCommit> getCommits(Map<String, Object> queryMap) throws EDBException {
List<JPACommit> commits = dao.getCommits(queryMap);
return new ArrayList<EDBCommit>(commits);
}
@Override
public JPACommit getLastCommitByKeyValue(String key, Object value) throws EDBException {
Map<String, Object> queryMap = new HashMap<String, Object>();
queryMap.put(key, value);
return getLastCommit(queryMap);
}
@Override
public JPACommit getLastCommit(Map<String, Object> queryMap) throws EDBException {
JPACommit result = dao.getLastCommit(queryMap);
return result;
}
@Override
public List<CommitMetaInfo> getRevisionsOfMatchingCommits(CommitQueryRequest request) throws EDBException {
getLogger().debug("Request revisions of matching commits for the request {}", request);
return dao.getRevisionsOfMatchingCommits(request);
}
@Override
public UUID getCurrentRevisionNumber() throws EDBException {
try {
return getCommit(System.currentTimeMillis()).getRevisionNumber();
} catch (EDBException e) {
getLogger().debug("There was no commit so far, so the current revision number is null");
return null;
}
}
@Override
public UUID getLastRevisionNumberOfContext(String contextId) throws EDBException {
try {
return getLastCommitByKeyValue("context", contextId).getRevisionNumber();
} catch (EDBException e) {
getLogger().debug("There was no commit so far under this context, so null is returned");
}
return null;
}
@Override
public JPACommit getCommit(Long from) throws EDBException {
List<JPACommit> commits = dao.getJPACommit(from);
if (commits == null || commits.size() == 0) {
throw new EDBException("There is no commit for this timestamp");
} else if (commits.size() > 1) {
throw new EDBException("There are more than one commit for one timestamp");
}
return commits.get(0);
}
@Override
public EDBCommit getCommitByRevision(String revision) throws EDBException {
return dao.getJPACommit(revision);
}
@Override
public Diff getDiff(Long firstTimestamp, Long secondTimestamp) throws EDBException {
List<EDBObject> headA = getHead(firstTimestamp);
List<EDBObject> headB = getHead(secondTimestamp);
return new Diff(getCommit(firstTimestamp), getCommit(secondTimestamp), headA, headB);
}
@Override
public List<String> getResurrectedOIDs() throws EDBException {
return dao.getResurrectedOIDs();
}
@Override
public List<EDBObject> getStateOfLastCommitMatching(
Map<String, Object> queryMap) throws EDBException {
JPACommit ci = getLastCommit(queryMap);
return getHead(ci.getTimestamp());
}
@Override
public List<EDBObject> getStateOfLastCommitMatchingByKeyValue(String key, Object value) throws EDBException {
Map<String, Object> query = new HashMap<String, Object>();
query.put(key, value);
return getStateOfLastCommitMatching(query);
}
@Override
public EDBCommit createEDBCommit(List<EDBObject> inserts, List<EDBObject> updates, List<EDBObject> deletes)
throws EDBException {
String committer = getAuthenticatedUser();
String contextId = getActualContextId();
JPACommit commit = new JPACommit(committer, contextId);
getLogger().debug("creating commit for committer {} with contextId {}", committer, contextId);
commit.insertAll(inserts);
commit.updateAll(updates);
commit.deleteAll(deletes);
commit.setHeadRevisionNumber(getCurrentRevisionNumber());
return commit;
}
/**
* Returns the actual authenticated user.
*/
private String getAuthenticatedUser() {
return (String) authenticationContext.getAuthenticatedPrincipal();
}
/**
* Returns the actual context id.
*/
private String getActualContextId() {
return ContextHolder.get().getCurrentContextId();
}
@Override
public void deleteCommit(UUID revision) throws EDBException {
if (revision == null) {
throw new EDBException("null revision not allowed");
}
JPACommit commit = dao.getJPACommit(revision.toString());
QueryRequest request =
QueryRequest.create().deleted().orJoined();
for (String oid : commit.getDeletions()) {
request.addParameter("oid", oid);
}
List<JPAObject> deletedObjects = dao.query(request);
performDeleteLogic(commit, deletedObjects);
}
}