SpringとJEEのCustomScopeの作成はほとんど同じです。 たとえば、次のアプリケーションの作成を検討してください。Webサービスには、スコープをアクティブにし、sessionId(conversationIdのアナログ)を返すメソッドがあります。 次に、このIDを使用して、スコープにデータを保存するメソッドを呼び出します。 次に、このデータを読み取るメソッドを呼び出して、スコープを閉じます。 どちらの場合もアーキテクチャは同じです:
- スコープのBeanを作成するクラスが作成され、登録されます。
- sessionIdパラメーターをインターセプトし、現在のスレッドのスコープ状態を設定するSOAPハンドラーが作成されます。
- スコープをアクティブ化および非アクティブ化するメソッドを含むWebサービスが作成されます
Springでは、Apache CXFを使用してWebサービスを作成し、JEEとの違いを最小限に抑えます。
スコープコンテキストクラスの作成。
コンテキストは、スコープのBeanを生成/保存/非アクティブ化するように設計されています。 ミサゴの各セッションは、ThreadLocal変数に格納されている特別なIDによって識別されます。 コンテキストはこのIDを読み取り、現在のセッションに対応するBeanのインスタンスを返します。これらのインスタンスは、Mapクラスのオブジェクトにローカルに保存されます。 つまり 各スレッドsessionIdは独自の値を持ち、コンテキストはBeanの対応するインスタンスを返します。 したがって、コンテキストには、セッションをアクティブ化および非アクティブ化するメソッドが含まれています。 これについてさらに詳しく説明します。 JEEでのアクティブ化と復号化のメソッドに加えて、Spring-
org.springframework.beans.factory.config.Scope
javax.enterprise.context.spi.Context
インターフェースを実装する必要があります。 これらのインターフェースは類似しているため、実装も非常に類似しています。 JEEの場合、Spring-WsScopeのWsContextクラスを作成します。 これらは次の部分で構成されています。
Beanセッションストレージ
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>>();
ここで、
instances
はマップであり、キーはセッションID、およびこのセッションのマップビン値です。 しかし、単にビンを参照するだけでは十分ではありません。 CDIビンを非アクティブにする場合、ビンが作成されたコンテキストを知る必要があります。したがって、InstanceInfoクラスが使用されます。ctxはコンテキストで、instanceはビンです。 mar binの鍵は
Contextual
オブジェクトです。
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 .
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 .