From a35f71964a139c70e17109b399c4b5e2285a9c5c Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 26 Aug 2015 00:44:32 +0200 Subject: [PATCH] Polishing --- .../validation/DataBinder.java | 2 +- .../springframework/core/AliasRegistry.java | 6 +- .../core/SimpleAliasRegistry.java | 32 +-- .../support/DefaultDataBinderFactory.java | 11 +- .../support/WebApplicationObjectSupport.java | 8 +- .../TilesConfigurerBeanDefinitionParser.java | 9 +- .../web/servlet/view/AbstractView.java | 4 +- .../sockjs/client/UndertowXhrTransport.java | 243 +++++++++--------- 8 files changed, 161 insertions(+), 154 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/validation/DataBinder.java b/spring-context/src/main/java/org/springframework/validation/DataBinder.java index 1e1172d792..95d6c47e7e 100644 --- a/spring-context/src/main/java/org/springframework/validation/DataBinder.java +++ b/spring-context/src/main/java/org/springframework/validation/DataBinder.java @@ -275,7 +275,7 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter { /** * Return the internal BindingResult held by this DataBinder, - * as AbstractPropertyBindingResult. + * as an AbstractPropertyBindingResult. */ protected AbstractPropertyBindingResult getInternalBindingResult() { if (this.bindingResult == null) { diff --git a/spring-core/src/main/java/org/springframework/core/AliasRegistry.java b/spring-core/src/main/java/org/springframework/core/AliasRegistry.java index 0e1e18bdaf..921b05caba 100644 --- a/spring-core/src/main/java/org/springframework/core/AliasRegistry.java +++ b/spring-core/src/main/java/org/springframework/core/AliasRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -44,10 +44,10 @@ public interface AliasRegistry { /** * Determine whether this given name is defines as an alias * (as opposed to the name of an actually registered component). - * @param beanName the bean name to check + * @param name the name to check * @return whether the given name is an alias */ - boolean isAlias(String beanName); + boolean isAlias(String name); /** * Return the aliases for the given name, if defined. diff --git a/spring-core/src/main/java/org/springframework/core/SimpleAliasRegistry.java b/spring-core/src/main/java/org/springframework/core/SimpleAliasRegistry.java index 1dfe2db56d..ba6c405ff5 100644 --- a/spring-core/src/main/java/org/springframework/core/SimpleAliasRegistry.java +++ b/spring-core/src/main/java/org/springframework/core/SimpleAliasRegistry.java @@ -144,6 +144,22 @@ public class SimpleAliasRegistry implements AliasRegistry { } } + /** + * Check whether the given name points back to the given alias as an alias + * in the other direction already, catching a circular reference upfront + * and throwing a corresponding IllegalStateException. + * @param name the candidate name + * @param alias the candidate alias + * @see #registerAlias + */ + protected void checkForAliasCircle(String name, String alias) { + if (alias.equals(canonicalName(name))) { + throw new IllegalStateException("Cannot register alias '" + alias + + "' for name '" + name + "': Circular reference - '" + + name + "' is a direct or indirect alias for '" + alias + "' already"); + } + } + /** * Determine the raw name, resolving aliases to canonical names. * @param name the user-specified name @@ -163,20 +179,4 @@ public class SimpleAliasRegistry implements AliasRegistry { return canonicalName; } - /** - * Check whether the given name points back to given alias as an alias - * in the other direction, catching a circular reference upfront and - * throwing a corresponding IllegalStateException. - * @param name the candidate name - * @param alias the candidate alias - * @see #registerAlias - */ - protected void checkForAliasCircle(String name, String alias) { - if (alias.equals(canonicalName(name))) { - throw new IllegalStateException("Cannot register alias '" + alias + - "' for name '" + name + "': Circular reference - '" + - name + "' is a direct or indirect alias for '" + alias + "' already"); - } - } - } diff --git a/spring-web/src/main/java/org/springframework/web/bind/support/DefaultDataBinderFactory.java b/spring-web/src/main/java/org/springframework/web/bind/support/DefaultDataBinderFactory.java index d673f17b2c..de00470231 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/support/DefaultDataBinderFactory.java +++ b/spring-web/src/main/java/org/springframework/web/bind/support/DefaultDataBinderFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,14 +30,17 @@ public class DefaultDataBinderFactory implements WebDataBinderFactory { private final WebBindingInitializer initializer; + /** - * Create new instance. - * @param initializer for global data binder intialization, or {@code null} + * Create a new {@code DefaultDataBinderFactory} instance. + * @param initializer for global data binder initialization + * (or {@code null} if none) */ public DefaultDataBinderFactory(WebBindingInitializer initializer) { this.initializer = initializer; } + /** * Create a new {@link WebDataBinder} for the given target object and * initialize it through a {@link WebBindingInitializer}. @@ -46,6 +49,7 @@ public class DefaultDataBinderFactory implements WebDataBinderFactory { @Override public final WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName) throws Exception { + WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest); if (this.initializer != null) { this.initializer.initBinder(dataBinder, webRequest); @@ -64,6 +68,7 @@ public class DefaultDataBinderFactory implements WebDataBinderFactory { */ protected WebDataBinder createBinderInstance(Object target, String objectName, NativeWebRequest webRequest) throws Exception { + return new WebRequestDataBinder(target, objectName); } diff --git a/spring-web/src/main/java/org/springframework/web/context/support/WebApplicationObjectSupport.java b/spring-web/src/main/java/org/springframework/web/context/support/WebApplicationObjectSupport.java index 1764b6ced9..209a87ddf0 100644 --- a/spring-web/src/main/java/org/springframework/web/context/support/WebApplicationObjectSupport.java +++ b/spring-web/src/main/java/org/springframework/web/context/support/WebApplicationObjectSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -125,7 +125,11 @@ public abstract class WebApplicationObjectSupport extends ApplicationObjectSuppo if (this.servletContext != null) { return this.servletContext; } - ServletContext servletContext = getWebApplicationContext().getServletContext(); + WebApplicationContext wac = getWebApplicationContext(); + if (wac == null) { + return null; + } + ServletContext servletContext = wac.getServletContext(); if (servletContext == null && isContextRequired()) { throw new IllegalStateException("WebApplicationObjectSupport instance [" + this + "] does not run within a ServletContext. Make sure the object is fully configured!"); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/TilesConfigurerBeanDefinitionParser.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/TilesConfigurerBeanDefinitionParser.java index 4baf6f6964..890e5333b9 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/TilesConfigurerBeanDefinitionParser.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/TilesConfigurerBeanDefinitionParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ import org.springframework.util.xml.DomUtils; /** * Parse the MVC namespace element and register - * TilesConfigurer bean + * a corresponding TilesConfigurer bean. * @author Rossen Stoyanchev * @since 4.1 @@ -49,11 +49,6 @@ public class TilesConfigurerBeanDefinitionParser extends AbstractSingleBeanDefin return BEAN_NAME; } - @Override - protected boolean shouldGenerateId() { - return super.shouldGenerateId(); - } - @Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { List childElements = DomUtils.getChildElementsByTagName(element, "definitions"); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractView.java index 715a994965..83eb924123 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractView.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -338,7 +338,7 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement /** * Create a RequestContext to expose under the specified attribute name. - *

Default implementation creates a standard RequestContext instance for the + *

The default implementation creates a standard RequestContext instance for the * given request and model. Can be overridden in subclasses for custom instances. * @param request current HTTP request * @param model combined output Map (never {@code null}), diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/UndertowXhrTransport.java b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/UndertowXhrTransport.java index 4c14937c16..205d71ef8b 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/UndertowXhrTransport.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/sockjs/client/UndertowXhrTransport.java @@ -90,10 +90,10 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra private static final AttachmentKey RESPONSE_BODY = AttachmentKey.create(String.class); - private final UndertowClient httpClient; - private final OptionMap optionMap; + private final UndertowClient httpClient; + private final XnioWorker worker; private final Pool bufferPool; @@ -104,9 +104,9 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra } public UndertowXhrTransport(OptionMap optionMap) throws IOException { - Assert.notNull(optionMap, "'optionMap' is required"); - this.httpClient = UndertowClient.getInstance(); + Assert.notNull(optionMap, "OptionMap is required"); this.optionMap = optionMap; + this.httpClient = UndertowClient.getInstance(); this.worker = Xnio.getInstance().createWorker(optionMap); this.bufferPool = new ByteBufferSlicePool(1048, 1048); } @@ -152,107 +152,6 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra } - @Override - protected ResponseEntity executeInfoRequestInternal(URI infoUrl) { - return executeRequest(infoUrl, Methods.GET, getRequestHeaders(), null); - } - - @Override - protected ResponseEntity executeSendRequestInternal(URI url, HttpHeaders headers, TextMessage message) { - return executeRequest(url, Methods.POST, headers, message.getPayload()); - } - - protected ResponseEntity executeRequest(URI url, HttpString method, HttpHeaders headers, String body) { - CountDownLatch latch = new CountDownLatch(1); - List responses = new CopyOnWriteArrayList(); - - try { - ClientConnection connection = this.httpClient.connect( - url, this.worker, this.bufferPool, this.optionMap).get(); - try { - ClientRequest request = new ClientRequest().setMethod(method).setPath(url.getPath()); - request.getRequestHeaders().add(HttpString.tryFromString(HttpHeaders.HOST), url.getHost()); - if (body != null && !body.isEmpty()) { - request.getRequestHeaders().add(HttpString.tryFromString(HttpHeaders.CONTENT_LENGTH), body.length()); - } - addHttpHeaders(request, headers); - connection.sendRequest(request, createRequestCallback(body, responses, latch)); - - latch.await(); - ClientResponse response = responses.iterator().next(); - HttpStatus status = HttpStatus.valueOf(response.getResponseCode()); - HttpHeaders responseHeaders = toHttpHeaders(response.getResponseHeaders()); - String responseBody = response.getAttachment(RESPONSE_BODY); - return (responseBody != null ? - new ResponseEntity(responseBody, responseHeaders, status) : - new ResponseEntity(responseHeaders, status)); - } - finally { - IoUtils.safeClose(connection); - } - } - catch (IOException ex) { - throw new SockJsTransportFailureException("Failed to execute request to " + url, ex); - } - catch (InterruptedException ex) { - throw new SockJsTransportFailureException("Interrupted while processing request to " + url, ex); - } - - } - - private ClientCallback createRequestCallback(final String body, - final List responses, final CountDownLatch latch) { - - return new ClientCallback() { - @Override - public void completed(ClientExchange result) { - result.setResponseListener(new ClientCallback() { - @Override - public void completed(final ClientExchange result) { - responses.add(result.getResponse()); - new StringReadChannelListener(result.getConnection().getBufferPool()) { - @Override - protected void stringDone(String string) { - result.getResponse().putAttachment(RESPONSE_BODY, string); - latch.countDown(); - } - @Override - protected void error(IOException ex) { - onFailure(latch, ex); - } - }.setup(result.getResponseChannel()); - } - @Override - public void failed(IOException ex) { - onFailure(latch, ex); - } - }); - try { - if (body != null) { - result.getRequestChannel().write(ByteBuffer.wrap(body.getBytes())); - } - result.getRequestChannel().shutdownWrites(); - if (!result.getRequestChannel().flush()) { - result.getRequestChannel().getWriteSetter() - .set(ChannelListeners.flushingChannelListener(null, null)); - result.getRequestChannel().resumeWrites(); - } - } - catch (IOException ex) { - onFailure(latch, ex); - } - } - @Override - public void failed(IOException ex) { - onFailure(latch, ex); - } - private void onFailure(CountDownLatch latch, IOException ex) { - latch.countDown(); - throw new SockJsTransportFailureException("Failed to execute request", ex); - } - }; - } - @Override protected void connectInternal(TransportRequest request, WebSocketHandler handler, URI receiveUrl, HttpHeaders handshakeHeaders, XhrClientSockJsSession session, @@ -265,24 +164,24 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra final SettableListenableFuture connectFuture) { if (logger.isTraceEnabled()) { - logger.trace("Starting XHR receive request, url=" + url); + logger.trace("Starting XHR receive request for " + url); } this.httpClient.connect( - new ClientCallback() { - @Override - public void completed(ClientConnection result) { - final ClientRequest httpRequest = new ClientRequest().setMethod(Methods.POST).setPath(url.getPath()); - httpRequest.getRequestHeaders().add(HttpString.tryFromString(HttpHeaders.HOST), url.getHost()); - addHttpHeaders(httpRequest, headers); - result.sendRequest(httpRequest, createConnectCallback(url, getRequestHeaders(), session, connectFuture)); - } - @Override - public void failed(IOException ex) { - throw new SockJsTransportFailureException("Failed to execute request to " + url, ex); - } - }, - url, this.worker, this.bufferPool, this.optionMap); + new ClientCallback() { + @Override + public void completed(ClientConnection result) { + final ClientRequest httpRequest = new ClientRequest().setMethod(Methods.POST).setPath(url.getPath()); + httpRequest.getRequestHeaders().add(HttpString.tryFromString(HttpHeaders.HOST), url.getHost()); + addHttpHeaders(httpRequest, headers); + result.sendRequest(httpRequest, createConnectCallback(url, getRequestHeaders(), session, connectFuture)); + } + @Override + public void failed(IOException ex) { + throw new SockJsTransportFailureException("Failed to execute request to " + url, ex); + } + }, + url, this.worker, this.bufferPool, this.optionMap); } @@ -329,10 +228,12 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra } }); } + @Override public void failed(IOException exc) { onFailure(exc); } + private void onFailure(Throwable failure) { if (connectFuture.setException(failure)) { return; @@ -348,6 +249,108 @@ public class UndertowXhrTransport extends AbstractXhrTransport implements XhrTra }; } + @Override + protected ResponseEntity executeInfoRequestInternal(URI infoUrl) { + return executeRequest(infoUrl, Methods.GET, getRequestHeaders(), null); + } + + @Override + protected ResponseEntity executeSendRequestInternal(URI url, HttpHeaders headers, TextMessage message) { + return executeRequest(url, Methods.POST, headers, message.getPayload()); + } + + protected ResponseEntity executeRequest(URI url, HttpString method, HttpHeaders headers, String body) { + CountDownLatch latch = new CountDownLatch(1); + List responses = new CopyOnWriteArrayList(); + + try { + ClientConnection connection = this.httpClient.connect(url, this.worker, + this.bufferPool, this.optionMap).get(); + try { + ClientRequest request = new ClientRequest().setMethod(method).setPath(url.getPath()); + request.getRequestHeaders().add(HttpString.tryFromString(HttpHeaders.HOST), url.getHost()); + if (body != null && !body.isEmpty()) { + request.getRequestHeaders().add(HttpString.tryFromString(HttpHeaders.CONTENT_LENGTH), body.length()); + } + addHttpHeaders(request, headers); + connection.sendRequest(request, createRequestCallback(body, responses, latch)); + + latch.await(); + ClientResponse response = responses.iterator().next(); + HttpStatus status = HttpStatus.valueOf(response.getResponseCode()); + HttpHeaders responseHeaders = toHttpHeaders(response.getResponseHeaders()); + String responseBody = response.getAttachment(RESPONSE_BODY); + return (responseBody != null ? + new ResponseEntity(responseBody, responseHeaders, status) : + new ResponseEntity(responseHeaders, status)); + } + finally { + IoUtils.safeClose(connection); + } + } + catch (IOException ex) { + throw new SockJsTransportFailureException("Failed to execute request to " + url, ex); + } + catch (InterruptedException ex) { + throw new SockJsTransportFailureException("Interrupted while processing request to " + url, ex); + } + } + + private ClientCallback createRequestCallback(final String body, + final List responses, final CountDownLatch latch) { + + return new ClientCallback() { + @Override + public void completed(ClientExchange result) { + result.setResponseListener(new ClientCallback() { + @Override + public void completed(final ClientExchange result) { + responses.add(result.getResponse()); + new StringReadChannelListener(result.getConnection().getBufferPool()) { + @Override + protected void stringDone(String string) { + result.getResponse().putAttachment(RESPONSE_BODY, string); + latch.countDown(); + } + @Override + protected void error(IOException ex) { + onFailure(latch, ex); + } + }.setup(result.getResponseChannel()); + } + @Override + public void failed(IOException ex) { + onFailure(latch, ex); + } + }); + try { + if (body != null) { + result.getRequestChannel().write(ByteBuffer.wrap(body.getBytes())); + } + result.getRequestChannel().shutdownWrites(); + if (!result.getRequestChannel().flush()) { + result.getRequestChannel().getWriteSetter() + .set(ChannelListeners.flushingChannelListener(null, null)); + result.getRequestChannel().resumeWrites(); + } + } + catch (IOException ex) { + onFailure(latch, ex); + } + } + + @Override + public void failed(IOException ex) { + onFailure(latch, ex); + } + + private void onFailure(CountDownLatch latch, IOException ex) { + latch.countDown(); + throw new SockJsTransportFailureException("Failed to execute request", ex); + } + }; + } + public class SockJsResponseListener implements ChannelListener {