JEEおよびSpringでカスタムスコープを作成する

スコープは、オブジェクトのライフサイクルを定義します。 たとえば、RequestScopeで定義されたJava Bean(以降、単にBean)は、http要求を受信すると作成され、この要求が完了すると解放されます。 JEEとSpringには、独自のスコープを作成する機能があります。 つまり 独自のライフサイクルでオブジェクトを作成できます。オブジェクトはイベントによって作成され、破棄されます。 JEEでは、CDI(Context and Dependency Injection)仕様がこれに責任を負っており、実際にはすでに1つの同様の組み込みスコープがあります。 これはConversationScopeです。 会話を開始および終了するためのAPIと注釈があります。 これらを使用しない場合、デフォルトでConversationScopeはRequestScopeのように動作します。 個々のクライアントの会話を追跡するために、特別なconversationIdが使用されます。通常、これはhttp要求パラメーターとして追加されます。 ただし、このアプローチはWebサービスでは機能しません。 そして、春にはそのようなものはまったくありません。 しかし、私の実務では、顧客は、外部システムへの同じ物理接続を複数の連続した呼び出しに使用するWebサービスを作成するように私に頼みました。 また、一定量の追加データを保存する必要がありました。 つまり Webサービスの会話スコープのような、特定の状態(接続とデータを持つオブジェクト)を特定の期間保存する必要がありました。 もちろん、このオブジェクトを3月に保存します。キーはアナログのconversationIdになり、MarをServleContextに入れて、すべてをWebサービスメソッドから取得できます。 しかし、それは不便です。 サーバー自体が、指定されたconversationIdに従ってオブジェクトを挿入する方がはるかに便利です。 したがって、SOAP Webサービスで機能するスコープを作成します。 Webサービス自体はスコープに属することはできませんが、Webサービスに注入するBeanはスコープに属します。



SpringとJEEのCustomScopeの作成はほとんど同じです。 たとえば、次のアプリケーションの作成を検討してください。Webサービスには、スコープをアクティブにし、sessionId(conversationIdのアナログ)を返すメソッドがあります。 次に、このIDを使用して、スコープにデータを保存するメソッドを呼び出します。 次に、このデータを読み取るメソッドを呼び出して、スコープを閉じます。 どちらの場合もアーキテクチャは同じです:



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 .



















All Articles