blob: e7853358ec31a0fa07b06859a2419e97e53cd67a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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.apache.servicecomb.edge.core;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.apache.servicecomb.common.rest.AbstractRestInvocation;
import org.apache.servicecomb.common.rest.RestConst;
import org.apache.servicecomb.common.rest.filter.HttpServerFilter;
import org.apache.servicecomb.common.rest.locator.OperationLocator;
import org.apache.servicecomb.common.rest.locator.ServicePathManager;
import org.apache.servicecomb.core.SCBEngine;
import org.apache.servicecomb.core.invocation.InvocationFactory;
import org.apache.servicecomb.core.provider.consumer.MicroserviceReferenceConfig;
import org.apache.servicecomb.core.provider.consumer.ReactiveResponseExecutor;
import org.apache.servicecomb.core.provider.consumer.ReferenceConfig;
import org.apache.servicecomb.foundation.vertx.executor.VertxContextExecutor;
import org.apache.servicecomb.foundation.vertx.http.VertxServerRequestToHttpServletRequest;
import org.apache.servicecomb.foundation.vertx.http.VertxServerResponseToHttpServletResponse;
import io.vertx.core.Vertx;
import io.vertx.ext.web.RoutingContext;
public class EdgeInvocation extends AbstractRestInvocation {
public static final String EDGE_INVOCATION_CONTEXT = "edgeInvocationContext";
protected String microserviceName;
protected MicroserviceReferenceConfig microserviceReferenceConfig;
protected String versionRule = null;
protected RoutingContext routingContext;
public void init(String microserviceName, RoutingContext context, String path,
List<HttpServerFilter> httpServerFilters) {
this.microserviceName = microserviceName;
this.requestEx = new VertxServerRequestToHttpServletRequest(context, path);
this.responseEx = new VertxServerResponseToHttpServletResponse(context.response());
this.routingContext = context;
this.httpServerFilters = httpServerFilters;
requestEx.setAttribute(RestConst.REST_REQUEST, requestEx);
}
public void edgeInvoke() {
findMicroserviceVersionMeta().whenCompleteAsync((r, e) -> {
if (e != null) {
sendFailResponse(e);
} else {
try {
microserviceReferenceConfig = r;
findRestOperation(microserviceReferenceConfig.getLatestMicroserviceMeta());
scheduleInvocation();
} catch (Throwable error) {
sendFailResponse(error);
}
}
}, VertxContextExecutor.create(Vertx.currentContext()));
}
protected CompletableFuture<MicroserviceReferenceConfig> findMicroserviceVersionMeta() {
return SCBEngine.getInstance()
.createMicroserviceReferenceConfigAsync(microserviceName, chooseVersionRule());
}
public void setVersionRule(String versionRule) {
this.versionRule = versionRule;
}
// another possible rule:
// path is: /msName/version/.....
// version in path is v1 or v2 and so on
// map version to VersionRule:
// v1->1.0.0-2.0.0
// v2->2.0.0-3.0.0
// that means if a(1.x.x) bigger then b(1.y.y), then a compatible to b
// but a(2.x.x) not compatible to b
protected String chooseVersionRule() {
// this will use all instance of the microservice
// and this required all new version compatible to old version
return versionRule;
}
@Override
protected OperationLocator locateOperation(ServicePathManager servicePathManager) {
return servicePathManager.consumerLocateOperation(requestEx.getRequestURI(), requestEx.getMethod());
}
@Override
protected void createInvocation() {
ReferenceConfig referenceConfig = microserviceReferenceConfig
.createReferenceConfig(restOperationMeta.getOperationMeta());
this.invocation = InvocationFactory.forConsumer(referenceConfig,
restOperationMeta.getOperationMeta(),
restOperationMeta.getOperationMeta().buildBaseConsumerRuntimeType(),
null);
this.invocation.setSync(false);
this.invocation.setEdge(true);
this.invocation.getHandlerContext().put(EDGE_INVOCATION_CONTEXT, Vertx.currentContext());
this.invocation.setResponseExecutor(new ReactiveResponseExecutor());
this.routingContext.put(RestConst.REST_INVOCATION_CONTEXT, invocation);
}
@Override
public void setContext() throws Exception {
// do not read InvocationContext from HTTP header, for security reason
}
}