Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
*
* 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.vmware.xenon.common;
import java.net.URI;
import java.util.EnumSet;
import java.util.List;
import com.vmware.xenon.common.Operation.AuthorizationContext;
import com.vmware.xenon.common.ServiceDocumentDescription.TypeName;
import com.vmware.xenon.services.common.QueryTask;
import com.vmware.xenon.services.common.QueryTask.Query;
import com.vmware.xenon.services.common.QueryTask.Query.Occurance;
import com.vmware.xenon.services.common.QueryTask.QuerySpecification.QueryOption;
import com.vmware.xenon.services.common.QueryTask.QueryTerm.MatchType;
import com.vmware.xenon.services.common.ServiceUriPaths;
/**
* Stateless helpers for transactions
*/
public final class TransactionServiceHelper {
private TransactionServiceHelper() {
}
interface Handler {
void handler(Operation op);
}
interface FailRequest {
void failRequest(Operation op, Throwable e, boolean shouldRetry);
}
/**
* Handles a GET request on a service that has pending transactions.
*
* If the request is transactional, we search for the latest version of the
* service tagged with the transaction and return it if exists; if it
* doesn't - we search for the latest non-shadowed version and return
* it if exists (otherwise we fail the request).
*
* If the request is non-transactional we search for the latest
* non-shadowed version and return it if exists, otherwise we fail the
* request.
*/
static void handleGetWithinTransaction(StatefulService s, Operation get,
Handler h, FailRequest fr, AuthorizationContext authContext) {
if (get.isWithinTransaction()) {
Operation inTransactionQueryOp = buildLatestInTransactionQueryTaskOp(s,
get.getTransactionId(), authContext).setCompletion((o, e) -> {
if (e != null) {
get.fail(e);
return;
}
QueryTask response = o.getBody(QueryTask.class);
if (response.results.documentLinks.isEmpty()) {
Operation nonTransactionQueryOp = buildLatestNonTransactionQueryTaskOp(
s, authContext).setCompletion((o2, e2) -> {
if (e2 != null) {
get.fail(e);
return;
}
QueryTask nonTransactionResponse = o2
.getBody(QueryTask.class);
returnLatestOrFail(nonTransactionResponse, get, fr);
});
s.sendRequest(nonTransactionQueryOp);
} else {
returnLatestOrFail(response, get, fr);
}
});
s.sendRequest(inTransactionQueryOp);
} else {
Operation nonTransactionQueryOp = buildLatestNonTransactionQueryTaskOp(s, authContext)
.setCompletion((o, e) -> {
if (e != null) {
get.fail(e);
return;
}
QueryTask response = o.getBody(QueryTask.class);
returnLatestOrFail(response, get, fr);
});
s.sendRequest(nonTransactionQueryOp);
}
}
private static void returnLatestOrFail(QueryTask response, Operation get, FailRequest fr) {
if (response.results.documentLinks.isEmpty()) {
get.setStatusCode(Operation.STATUS_CODE_NOT_FOUND);
fr.failRequest(get, new IllegalStateException("Latest state not found"), false);
return;
}
String latest = response.results.documentLinks.get(0);
Object obj = response.results.documents.get(latest);
get.setBodyNoCloning(obj).complete();
}
private static Operation buildLatestInTransactionQueryTaskOp(StatefulService s, String txid,
AuthorizationContext authContext) {
Query.Builder queryBuilder = Query.Builder.create();
queryBuilder.addFieldClause(ServiceDocument.FIELD_NAME_SELF_LINK, s.getSelfLink());
queryBuilder.addFieldClause(ServiceDocument.FIELD_NAME_TRANSACTION_ID, txid);
QueryTask.Builder queryTaskBuilder = QueryTask.Builder.createDirectTask()
.setQuery(queryBuilder.build());
queryTaskBuilder.addOption(QueryOption.EXPAND_CONTENT);
queryTaskBuilder.addOption(QueryOption.INCLUDE_ALL_VERSIONS);
queryTaskBuilder.orderDescending(ServiceDocument.FIELD_NAME_VERSION, TypeName.LONG);
QueryTask task = queryTaskBuilder.build();
Operation returnOp = Operation
.createPost(s.getHost(), ServiceUriPaths.CORE_QUERY_TASKS)
.setBody(task);
returnOp.setAuthorizationContext(authContext);
return returnOp;
}
private static Operation buildLatestNonTransactionQueryTaskOp(StatefulService s,
AuthorizationContext authContext) {
Query.Builder queryBuilder = Query.Builder.create();
queryBuilder.addFieldClause(ServiceDocument.FIELD_NAME_SELF_LINK, s.getSelfLink());
queryBuilder.addFieldClause(ServiceDocument.FIELD_NAME_TRANSACTION_ID, "*",
MatchType.WILDCARD, Occurance.MUST_NOT_OCCUR);
QueryTask.Builder queryTaskBuilder = QueryTask.Builder.createDirectTask()
.setQuery(queryBuilder.build());
queryTaskBuilder.addOption(QueryOption.EXPAND_CONTENT);
queryTaskBuilder.addOption(QueryOption.INCLUDE_ALL_VERSIONS);
queryTaskBuilder.orderDescending(ServiceDocument.FIELD_NAME_VERSION, TypeName.LONG);
QueryTask task = queryTaskBuilder.build();
Operation returnOp = Operation
.createPost(s.getHost(), ServiceUriPaths.CORE_QUERY_TASKS)
.setBody(task);
returnOp.setAuthorizationContext(authContext);
return returnOp;
}
/**
* Notify the transaction coordinator
*/
static Operation notifyTransactionCoordinatorOp(StatefulService s, Operation op, Throwable e) {
URI txCoordinator = UriUtils.buildTransactionUri(s.getHost(), op.getTransactionId());
s.addPendingTransaction(txCoordinator.getPath());
Operation.TransactionContext operationsLogRecord = new Operation.TransactionContext();
operationsLogRecord.action = op.getAction();
operationsLogRecord.isSuccessful = e == null;
Operation notifyCoordinatorOp = Operation.createPut(txCoordinator).setTransactionId(null);
notifyCoordinatorOp.addRequestHeader(Operation.TRANSACTION_REFLINK_HEADER, s.getSelfLink());
return s.setPendingTransactionsAsBody(notifyCoordinatorOp, operationsLogRecord);
}
/**
* Notify the transaction coordinator of a new service
*/
static Operation notifyTransactionCoordinatorOfNewServiceOp(FactoryService factoryService,
Service childService, Operation op) {
// some of the basic properties of the child service being created are not
// yet set at the point we're intercepting the POST, so we need to set them here
childService.setHost(factoryService.getHost());
URI childServiceUri = op.getUri().normalize();
String childServicePath = UriUtils.normalizeUriPath(childServiceUri.getPath());
childService.setSelfLink(childServicePath);
// TODO: remove cast by changing childService type at the origin (FactoryService)
return notifyTransactionCoordinatorOp((StatefulService) childService, op, null);
}
/**
* Check whether it's a transactional control operation (i.e., expose shadowed state, abort
* etc.), and take appropriate action
*/
static boolean handleOperationInTransaction(StatefulService s,
Class extends ServiceDocument> st,
Operation request, AuthorizationContext authContext) {
if (request.getRequestHeaderAsIs(Operation.TRANSACTION_HEADER) == null) {
return false;
}
if (request.getRequestHeaderAsIs(Operation.TRANSACTION_HEADER)
.equals(Operation.TX_ENSURE_COMMIT)) {
// this request is targeting a transaction service - let it 'fall through'
return false;
}
if (request.getRequestHeaderAsIs(Operation.TRANSACTION_HEADER).equals(
Operation.TX_COMMIT)) {
// commit should expose latest state, i.e., remove shadow and bump the version
// and remove transaction from pending
String txRefLink = request.getRequestHeader(Operation.TRANSACTION_REFLINK_HEADER);
s.removePendingTransaction(txRefLink);
s.getHost().clearTransactionalCachedServiceState(s,
UriUtils.getLastPathSegment(txRefLink));
QueryTask.QuerySpecification q = new QueryTask.QuerySpecification();
QueryTask.Query txnIdClause = new QueryTask.Query().setTermPropertyName(
ServiceDocument.FIELD_NAME_TRANSACTION_ID)
.setTermMatchValue(UriUtils.getLastPathSegment(txRefLink));
txnIdClause.occurance = QueryTask.Query.Occurance.MUST_OCCUR;
q.query.addBooleanClause(txnIdClause);
QueryTask.Query selfLinkClause = new QueryTask.Query().setTermPropertyName(
ServiceDocument.FIELD_NAME_SELF_LINK)
.setTermMatchValue(s.getSelfLink());
selfLinkClause.occurance = QueryTask.Query.Occurance.MUST_OCCUR;
q.query.addBooleanClause(selfLinkClause);
q.options = EnumSet.of(QueryTask.QuerySpecification.QueryOption.EXPAND_CONTENT,
QueryTask.QuerySpecification.QueryOption.INCLUDE_ALL_VERSIONS);
QueryTask task = QueryTask.create(q).setDirect(true);
URI uri = UriUtils.buildUri(s.getHost(), ServiceUriPaths.CORE_QUERY_TASKS);
Operation startPost = Operation
.createPost(uri)
.setBody(task)
.setCompletion((o, f) -> unshadowQueryCompletion(s, st, o, f, request));
startPost.setAuthorizationContext(authContext);
s.sendRequest(startPost);
} else if (request.getRequestHeaderAsIs(Operation.TRANSACTION_HEADER).equals(
Operation.TX_ABORT)) {
// abort should just remove transaction from pending
String txRefLink = request.getRequestHeader(Operation.TRANSACTION_REFLINK_HEADER);
s.removePendingTransaction(txRefLink);
s.getHost().clearTransactionalCachedServiceState(s,
UriUtils.getLastPathSegment(txRefLink));
request.complete();
} else {
request.fail(new IllegalArgumentException(
"Transaction control message, but none of {commit, abort}"));
}
return true;
}
static void unshadowQueryCompletion(StatefulService s,
Class extends ServiceDocument> st,
Operation o, Throwable f,
Operation original) {
if (f != null) {
s.logInfo(f.toString());
original.fail(f);
return;
}
QueryTask response = o.getBody(QueryTask.class);
if (response.results.documentLinks.isEmpty()) {
// TODO: When implement 2PC, abort entire transaction
original.fail(new IllegalStateException(
"There should be at least one shadowed, but none was found"));
return;
}
// Whereas, if more than a single version, get the latest..
List dl = response.results.documentLinks;
String latest = dl.get(0);
Object obj = response.results.documents.get(latest);
// ..unshadow..
ServiceDocument sd = Utils.fromJson(obj, st);
sd.documentTransactionId = null;
// ..and stick back in.
s.setState(original, sd);
original.complete();
}
}