📜 ⬆️ ⬇️

Creating a Custom Scope in JEE and Spring

Scope determines the life cycle of an object. For example, a java-bin (hereinafter just a bin) defined in RequestScope is created when an http request is received and is released when the request is completed. In JEE and in Spring there is an opportunity to create your own scope. Those. we can create objects with our own life cycle - they will be created for any of our events and also destroyed. In JEE, the CDI (Context and Dependency Injection) specification is responsible for this, and in fact there already exists one such built-in scope. This is a ConversationScope. We have API and annotations for starting and ending a conversation. If we do not use them, then by default ConversationScope behaves like RequestScope. To track the conversation of each individual client, a special conversationId is used, which is usually added as an http request parameter. But this approach does not work for web services. And in Spring there is nothing like that at all. But in my practice, the customer asked to make a web service that would use the same physical connection to the external system for several consecutive calls. It was also necessary to store some amount of additional data. Those. it was necessary to save a certain state (an object with a connection and data) for a certain period of time, such an analogue of the conversation scope for the web service. You can, of course, save this object in Mar, where our analogue of conversationId will be the key, and Mar will be put into ServleContext and get it all from the methods of the web service. But it is inconvenient. It is much more convenient when the server itself will inject us our object in a given conversationId. Therefore, let's make our scope, which will work with the SOAP web service. The web service itself cannot belong to any scope, but our bin, which we will inject into the web service, will belong to our scope.

Creating CustomScope for Spring and JEE is almost the same. For example, consider the creation of the following application: our web service will have a method that activates our scope and returns sessionId (analog of conversationId). Then, using this id, we will call a method that will store the data in our scope. Then we call the method that reads this data, and then close the scope. The architecture in both cases is the same:
.
In Spring, to create a web service, we will use Apache CXF to minimize the differences from JEE.

Creating context class scope.


The context is intended to generate / store / deactivate bins of our scope. Each session in our Osprey is identified by a special id, which is stored in the ThreadLocal variable. The context reads this id returns the bin instances of the corresponding current session, which are stored locally in the object of the Map class. Those. each sessionId thread will have its own value and the context will return the corresponding instances of the beans. Accordingly, the context contains methods for activating and deactivating the session. Now about this in more detail. In addition to the methods for activating and de-activating in JEE, we need to implement the javax.enterprise.context.spi.Context interface, in Spring - org.springframework.beans.factory.config.Scope . These interfaces are similar, so the implementations are also very similar. For JEE we will make a class WsContext, for Spring - WsScope. They consist of the following parts:
Storage session bins

in JEE:

 private static class InstanceInfo<T> { public CreationalContext<T> ctx; public T instance; } private Map<String, Map<Contextual, InstanceInfo>> instances = new HashMap<SessionId, Map<Contextual, InstanceInfo>>(); 

Here instances is a Map, where the key is the session id, and the Map value of the bins for this session. But just references to bin are not enough for us When you deactivate a CDI bean, you need to know the context in which the given bean was created, which is why the InstanceInfo class is used, in ctoro, ctx is the context, and instance is bin. The key to Marin Bins is a Contextual object.
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();
, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();
, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();
, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .

Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .

Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .

Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .

Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .

Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .

Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
 Contextual –  ,  CDI     .  , CDI       T,    Contextual (Bean, Decorator, Interceptor) 
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .
Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .

Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .

Contextual – , CDI . , CDI T, Contextual (Bean, Decorator, Interceptor)
Spring:
private Map<String, Map<String, Object>> instances = new HashMap<String, Map<String, Object>>();

, Spring .

.
, id ThreadLocal . Spring JEE .
private final ThreadLocal<String> currentSessionId = new ThreadLocal<String>() { protected String initialValue() { return null; } }; public String getCurrentSessionId() { return currentSessionId.get(); } public void setCurrentSessionId(String currentSessionId) { this.currentSessionId.set(currentSessionId); }


JEE Spring. Map id .
public void activate(String sessionId) { Map<Contextual, InstanceInfo> map = new HashMap<Contextual, InstanceInfo>(); instances.put(sessionId, map); this.currentSessionId.set(sessionId); }
JEE , JEE :
@Override public boolean isActive() { String id = currentSessionId.get(); return instances.containsKey(id); }


JEE
public void deactivate() { String id = currentSessionId.get(); Map<Contextual, InstanceInfo> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Set<Contextual> keySet = map.keySet(); for (Contextual contextual : keySet) { InstanceInfo instanceInfo = map.get(contextual); contextual.destroy(instanceInfo.instance, instanceInfo.ctx); } currentSessionId.set(null); instances.remove(id); }
JEE , . @PreDestroy garbage collector. JEE , , , .

Spring
:
public void deactivate() { String id = currentSessionId.get(); Thread currentThread = Thread.currentThread(); Map<String, Object> map = instances.get(id); if (map == null) { throw new RuntimeException("WsScope with id =" + id + " doesn't exist"); } Map<String, Object> objectsMap = instances.get(id); Set<String> keySet = objectsMap.keySet(); for (String name : keySet) { remove(name); } instances.remove(id); currentSessionId.set(null); }
JEE, Spring remove . Scope , .
public Object remove(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } Runnable runnable = destructionCollbacks.get(name); Thread t = new Thread(runnable); t.start(); return map.remove(name); }
destructionCallbacks :
private Map<String, Runnable> destructionCollbacks = new HashMap<>();
Scope
public void registerDestructionCallback(String name, Runnable callback) { destructionCollbacks.put(name, callback); }
, callback, Spring, , registerDestructionCallback . , JEE, . .. custom scope Spring.


JEE

public <T> T get(Contextual<T> contextual), public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext)
, . null, , .
@Override public <T> T get(Contextual<T> contextual) { Map<Contextual,InstanceInfo> map = instances.get(currentSessionId.get()); if (map == null) { return null; } InstanceInfo<T> info = map.get(contextual); if (info == null) { return null; } return info.instance; } @Override public <T> T get(Contextual<T> contextual, CreationalContext<T> creationalContext) { T instance = contextual.create(creationalContext); InstanceInfo<T> info = new InstanceInfo<T>(); info.ctx = creationalContext; info.instance = instance; Map<Contextual, InstanceInfo> map = nstances.get(currentSessionId.get()); if (map == null) { map= new HashMap<Contextual, Context.InstanceInfo>(); instances.put(currentSessionId.get(), map); } map.put(contextual, info); return instance; }
Spring
Spring get resolveContextualObject . resolveContextualObject Spring custom scope. , . , , .. null. get . get .
public Object get(String name, ObjectFactory<?> objectFactory) { Object object = resolveContextualObject(name); if (object != null) { return object; } String sessionId = currentSessionId.get(); if (sessionId == null) { throw new RuntimeException("WsScope is inactive"); } Map<String, Object> map = instances.get(sessionId); if (map == null) { throw new RuntimeException("WsScope is inactive"); } object = objectFactory.getObject(); map.put(name, object); return object; } public Object resolveContextualObject(String name) { String sessionId = currentSessionId.get(); if (sessionId == null) { return null; } Map<String, Object> map = instances.get(sessionId); if (map == null) { return null; } Object object = map.get(name); return object; }
org.springframework.beans.factory.config.Scope : public String getConversationId() . , , javadoc, .
public String getConversationId() { return currentSessionId.get(); }

scope
JEE
JEE , , scope.
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @NormalScope public @interface WsScope { }
scope. :
@Override public Class<? extends Annotation> getScope() { return WsScope.class; }
Spring
Spring scope , , .

(scope)
JEE
JEE CDI Extension. , Extension
public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm)
:
context = new WsContext(); abd.addContext(context);
extension /META-INF/services/javax.enterprise.inject.spi.Extension . extension .
Extension :

public class WsExtension implements Extension { private WsContext context; public WsContext getContext() { return context; } public void afterBeanDiscovery(@Observes AfterBeanDiscovery abd, BeanManager bm) { context = new WsContext(); abd.addContext(context); } }

Spring
Spring scope.
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer"> <property name="scopes"> <map> <entry key="WsScope"> <bean class="com.dataart.customscope.spring.context.WsScope" /> </entry> </map> </property> </bean>
scope Singleton.


scope .
JEE
JEE , WsExtension. , scope. WsContext Extension. Producer:
public class WsContextProducer { @Inject private WsExtension ext; @Produces public WsContext getContext() { return ext.getContext(); } }
manged bean JEE scope Default ( ). , - CDI WsScope : default Producer. , , .. Producer. , CDI . JEE7 @Vetoed . .. :
@Vetoed public class WsContext implements Context {...}
:
@Inject private WsContext context;
Spring
.. scope , :
@Autowired private WsScope scope;

scope
-, id ws-session-id. - , id . .. . id , id ( ), . id , activate() . id, . - , . deactivate() . - ( WsService) scope. -. .. id - , id.
JEE
@WsScope public class WsService { ... }
-:
@WebService() @HandlerChain(file = "wshandler.xml", name = "") public class WsScopeTest { private static int id = 0; @Inject private WsContext context; @Inject private WsService srv; @WebMethod() public String startWsScope() { String sessionId = String.valueOf(id++); context.activate(sessionId); return sessionId; } @WebMethod() public void endWsScope(@WebParam(name = "ws-session-id") String sessionId) { context.deactivate(); } @WebMethod() public void setName(@WebParam(name = "ws-session-id") String sessionId, @WebParam(name = "name")String name) { srv.setName(name); } @WebMethod() public String sayHello(@WebParam(name = "ws-session-id") String sessionId) { return srv.hello(); } }
:
public class WsCdiSoapHandler implements SOAPHandler<SOAPMessageContext> { private static final Logger LOGGER = Logger.getLogger(WsCdiSoapHandler.class.getName()); @Inject private WsContext context; @Override public void close(MessageContext ctx) { } @Override public boolean handleFault(SOAPMessageContext ctx) { return true; } @Override public boolean handleMessage(SOAPMessageContext ctx) { Boolean outbound = (Boolean) ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); SOAPMessage message = ctx.getMessage(); SOAPBody soapBody; try { soapBody = message.getSOAPBody(); } catch (SOAPException e) { e.printStackTrace(); return false; } String methodName = null; NodeList nodes = soapBody.getChildNodes(); methodName = findMethodName(methodName, nodes); if (outbound) { LOGGER.fine("[OUT] " + methodName.replace("Response", "")); return true; } LOGGER.fine("[IN] " + methodName); String sessionId = findSessionId(nodes); context.setCurrentSessionId(sessionId); LOGGER.fine("Handler. Id=" + sessionId); return true; } private String findMethodName(String methodName, NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if (Node.ELEMENT_NODE == node.getNodeType()) { methodName = node.getLocalName(); } } return methodName; } private String findSessionId(NodeList nodes) { for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); if ("ws-session-id".equals(node.getLocalName())) { Node firstChild = node.getFirstChild(); if (firstChild == null) { return null; } return firstChild.getNodeValue(); } NodeList childNodes = node.getChildNodes(); String id = findSessionId(childNodes); if (id != null) { return id; } } return null; } @Override public Set<QName> getHeaders() { return null; } }
Spring
Spring . @Inject @Autowired , - - .
:
@Service @Scope(value = "WsScope", proxyMode = ScopedProxyMode.TARGET_CLASS) public class WsService { ... }
- proxyMode = ScopedProxyMode.TARGET_CLASS ! , , .. - , . , .
- :
<jaxws:endpoint id="testWsService" implementor="#testWS" address="/WsTest" publish="true"> <jaxws:handlers> <bean class="com.dataart.customscope.spring.context.WsSoapHandler"></bean> </jaxws:handlers> </jaxws:endpoint> <bean id="testWS" class="com.dataart.customscope.spring.testapp.WsTest"></bean>
, , @Autowired .



custom scope JEE Spring . . JEE, , - , - JEE .

')

Source: https://habr.com/ru/post/220233/


All Articles