Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .artifacts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ dubbo-xds
dubbo-plugin-loom
dubbo-rest-jaxrs
dubbo-rest-spring
dubbo-rest-spring6
dubbo-rest-openapi
dubbo-triple-servlet
dubbo-triple-websocket
Original file line number Diff line number Diff line change
Expand Up @@ -82,28 +82,39 @@ public FrameworkModel() {
this.setInternalId(String.valueOf(index.getAndIncrement()));
// register FrameworkModel instance early
allInstances.add(this);
if (LOGGER.isInfoEnabled()) {
LOGGER.info(getDesc() + " is created");
}
initialize();
try {
if (LOGGER.isInfoEnabled()) {
LOGGER.info(getDesc() + " is created");
}
initialize();

TypeDefinitionBuilder.initBuilders(this);
TypeDefinitionBuilder.initBuilders(this);

serviceRepository = new FrameworkServiceRepository(this);
serviceRepository = new FrameworkServiceRepository(this);

ExtensionLoader<ScopeModelInitializer> initializerExtensionLoader =
this.getExtensionLoader(ScopeModelInitializer.class);
Set<ScopeModelInitializer> initializers = initializerExtensionLoader.getSupportedExtensionInstances();
for (ScopeModelInitializer initializer : initializers) {
initializer.initializeFrameworkModel(this);
}
ExtensionLoader<ScopeModelInitializer> initializerExtensionLoader =
this.getExtensionLoader(ScopeModelInitializer.class);
Set<ScopeModelInitializer> initializers =
initializerExtensionLoader.getSupportedExtensionInstances();
for (ScopeModelInitializer initializer : initializers) {
initializer.initializeFrameworkModel(this);
}

internalApplicationModel = new ApplicationModel(this, true);
internalApplicationModel
.getApplicationConfigManager()
.setApplication(new ApplicationConfig(
internalApplicationModel, CommonConstants.DUBBO_INTERNAL_APPLICATION));
internalApplicationModel.setModelName(CommonConstants.DUBBO_INTERNAL_APPLICATION);
internalApplicationModel = new ApplicationModel(this, true);
internalApplicationModel
.getApplicationConfigManager()
.setApplication(new ApplicationConfig(
internalApplicationModel, CommonConstants.DUBBO_INTERNAL_APPLICATION));
internalApplicationModel.setModelName(CommonConstants.DUBBO_INTERNAL_APPLICATION);
} catch (RuntimeException | Error e) {
destroy();
allInstances.remove(this);
if (defaultInstance == this) {
defaultInstance = null;
resetDefaultFrameworkModel();
}
throw e;
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* 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.dubbo.rpc.model;

import org.apache.dubbo.common.resource.Disposable;

public class FailingScopeModelInitializer implements ScopeModelInitializer, Disposable {

private static volatile boolean fail;
private static volatile boolean destroyed;

static void setFail(boolean fail) {
FailingScopeModelInitializer.fail = fail;
if (fail) {
destroyed = false;
}
}

static boolean isDestroyed() {
return destroyed;
}

@Override
public void initializeFrameworkModel(FrameworkModel frameworkModel) {
if (fail) {
throw new IllegalStateException("Expected framework model initialization failure");
}
}

@Override
public void destroy() {
destroyed = true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,20 @@
import org.apache.dubbo.common.extension.ExtensionScope;
import org.apache.dubbo.common.utils.StringUtils;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

/**
* {@link FrameworkModel}
*/
class FrameworkModelTest {
@AfterEach
void tearDown() {
FailingScopeModelInitializer.setFail(false);
FrameworkModel.destroyAll();
}

@Test
void testInitialize() {
FrameworkModel.destroyAll();
Expand Down Expand Up @@ -60,6 +67,25 @@ void testDefaultModel() {
frameworkModel.destroy();
}

@Test
void testInitializationFailureRollsBackRegisteredInstance() {
FrameworkModel.destroyAll();
FailingScopeModelInitializer.setFail(true);

IllegalStateException exception =
Assertions.assertThrows(IllegalStateException.class, FrameworkModel::defaultModel);
Assertions.assertEquals("Expected framework model initialization failure", exception.getMessage());
Assertions.assertTrue(FrameworkModel.getAllInstances().isEmpty());
Assertions.assertTrue(FailingScopeModelInitializer.isDestroyed());

FailingScopeModelInitializer.setFail(false);
FrameworkModel frameworkModel = FrameworkModel.defaultModel();

Assertions.assertEquals(1, FrameworkModel.getAllInstances().size());
Assertions.assertSame(frameworkModel, FrameworkModel.getAllInstances().get(0));
Assertions.assertNotNull(frameworkModel.getInternalApplicationModel());
}

@Test
void testApplicationModel() {
FrameworkModel frameworkModel = new FrameworkModel();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
failing=org.apache.dubbo.rpc.model.FailingScopeModelInitializer
8 changes: 0 additions & 8 deletions dubbo-distribution/dubbo-all-shaded/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -275,13 +275,6 @@
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rest-spring</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rest-openapi</artifactId>
Expand Down Expand Up @@ -540,7 +533,6 @@
<include>org.apache.dubbo:dubbo-rpc-injvm</include>
<include>org.apache.dubbo:dubbo-rpc-triple</include>
<include>org.apache.dubbo:dubbo-rest-jaxrs</include>
<include>org.apache.dubbo:dubbo-rest-spring</include>
<include>org.apache.dubbo:dubbo-rest-openapi</include>
<include>org.apache.dubbo:dubbo-triple-servlet</include>
<include>org.apache.dubbo:dubbo-triple-websocket</include>
Expand Down
8 changes: 0 additions & 8 deletions dubbo-distribution/dubbo-all/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -275,13 +275,6 @@
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rest-spring</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rest-openapi</artifactId>
Expand Down Expand Up @@ -539,7 +532,6 @@
<include>org.apache.dubbo:dubbo-rpc-injvm</include>
<include>org.apache.dubbo:dubbo-rpc-triple</include>
<include>org.apache.dubbo:dubbo-rest-jaxrs</include>
<include>org.apache.dubbo:dubbo-rest-spring</include>
<include>org.apache.dubbo:dubbo-rest-openapi</include>
<include>org.apache.dubbo:dubbo-triple-servlet</include>
<include>org.apache.dubbo:dubbo-triple-websocket</include>
Expand Down
5 changes: 5 additions & 0 deletions dubbo-distribution/dubbo-bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,11 @@
<artifactId>dubbo-rest-spring</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rest-spring6</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rest-openapi</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,13 @@ public void onResponse(Result result, HttpRequest request, HttpResponse response
}

@Override
public void onError(Throwable t, HttpRequest request, HttpResponse response) {
public void onErrorResult(Throwable t, Result result, HttpRequest request, HttpResponse response) {
if (exceptionType.isInstance(t)) {
try (Response r = extension.toResponse(t)) {
response.setBody(Helper.toBody(r));
Object body = Helper.toBody(r);
response.setBody(body);
result.setValue(body);
result.setException(null);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* 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.dubbo.rpc.protocol.tri.rest.support.jaxrs.filter;

import org.apache.dubbo.remoting.http12.HttpRequest;
import org.apache.dubbo.remoting.http12.HttpResponse;
import org.apache.dubbo.remoting.http12.HttpResult;
import org.apache.dubbo.rpc.AppResponse;
import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter;

import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

class ExceptionMapperAdapterTest {

@Test
@SuppressWarnings({"rawtypes", "unchecked"})
void explicitlyResolvesTheCompletionResult() throws Exception {
RestFilter filter = new ExceptionMapperAdapter().adapt((ExceptionMapper) new TestExceptionMapper());
RestFilter.Listener listener = (RestFilter.Listener) filter;
IllegalArgumentException failure = new IllegalArgumentException("failure");
AppResponse result = new AppResponse(failure);
HttpRequest request = mock(HttpRequest.class);
HttpResponse response = mock(HttpResponse.class);

listener.onErrorResult(failure, result, request, response);

assertFalse(result.hasException());
HttpResult<?> body = (HttpResult<?>) result.getValue();
assertSame("handled", body.getBody());
verify(response).setBody(body);
}

private static final class TestExceptionMapper implements ExceptionMapper<IllegalArgumentException> {
@Override
public Response toResponse(IllegalArgumentException exception) {
return Response.status(409).entity("handled").build();
}
}
}
6 changes: 6 additions & 0 deletions dubbo-plugin/dubbo-rest-spring/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@
<artifactId>log4j-slf4j-impl</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,12 @@
import javax.servlet.http.HttpServletResponse;

import java.util.Arrays;
import java.util.concurrent.atomic.AtomicLong;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

@Activate(onClass = "org.springframework.web.servlet.HandlerInterceptor")
@Activate(onClass = {"org.springframework.web.servlet.HandlerInterceptor", "javax.servlet.http.HttpServletRequest"})
public final class HandlerInterceptorAdapter implements RestExtensionAdapter<HandlerInterceptor> {
@Override
public boolean accept(Object extension) {
Expand All @@ -49,7 +50,12 @@ public RestFilter adapt(HandlerInterceptor extension) {

private static final class HandlerInterceptorRestFilter implements RestFilter, Listener {

private static final AtomicLong ATTRIBUTE_ID = new AtomicLong();
private static final String ABORTED_ATTRIBUTE = HandlerInterceptorRestFilter.class.getName() + ".aborted";

private final HandlerInterceptor interceptor;
private final String appliedAttribute =
HandlerInterceptorRestFilter.class.getName() + ".applied." + ATTRIBUTE_ID.incrementAndGet();

@Override
public int getPriority() {
Expand All @@ -69,27 +75,48 @@ public HandlerInterceptorRestFilter(HandlerInterceptor interceptor) {
public void doFilter(HttpRequest request, HttpResponse response, FilterChain chain) throws Exception {
Object handler = request.attribute(RestConstants.HANDLER_ATTRIBUTE);
if (interceptor.preHandle((HttpServletRequest) request, (HttpServletResponse) response, handler)) {
request.setAttribute(appliedAttribute, Boolean.TRUE);
chain.doFilter(request, response);
} else {
request.setAttribute(ABORTED_ATTRIBUTE, Boolean.TRUE);
}
}

@Override
public void onResponse(Result result, HttpRequest request, HttpResponse response) throws Exception {
if (result.hasException()) {
onError(result.getException(), request, response);
if (!isApplied(request)
|| Boolean.TRUE.equals(request.attribute(ABORTED_ATTRIBUTE))
|| result.hasException()) {
return;
}
Object handler = request.attribute(RestConstants.HANDLER_ATTRIBUTE);
ModelAndView mv = new ModelAndView();
mv.addObject("result", result);
interceptor.postHandle((HttpServletRequest) request, (HttpServletResponse) response, handler, mv);
try {
interceptor.postHandle((HttpServletRequest) request, (HttpServletResponse) response, handler, mv);
} catch (Throwable t) {
result.setException(t);
}
}

@Override
public void onError(Throwable t, HttpRequest request, HttpResponse response) throws Exception {
Object handler = request.attribute(RestConstants.HANDLER_ATTRIBUTE);
Exception ex = t instanceof Exception ? (Exception) t : new RpcException(t);
interceptor.afterCompletion((HttpServletRequest) request, (HttpServletResponse) response, handler, ex);
public void afterCompletion(Result result, HttpRequest request, HttpResponse response) throws Exception {
try {
if (!isApplied(request)) {
return;
}
Object handler = request.attribute(RestConstants.HANDLER_ATTRIBUTE);
Throwable t = result.getException();
Exception ex = t == null ? null : t instanceof Exception ? (Exception) t : new RpcException(t);
interceptor.afterCompletion((HttpServletRequest) request, (HttpServletResponse) response, handler, ex);
} finally {
request.removeAttribute(appliedAttribute);
request.removeAttribute(ABORTED_ATTRIBUTE);
}
}

private boolean isApplied(HttpRequest request) {
return Boolean.TRUE.equals(request.attribute(appliedAttribute));
}

@Override
Expand Down
Loading
Loading