рдЬреЗрдИрдИ рдФрд░ рд╕реНрдкреНрд░рд┐рдВрдЧ рдореЗрдВ рдХрд╕реНрдЯрдо рд╕реНрдХреЛрдк рдмрдирд╛рдирд╛

рд╕реНрдХреЛрдк рдХрд┐рд╕реА рд╡рд╕реНрддреБ рдХреЗ рдЬреАрд╡рди рдЪрдХреНрд░ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, RequestScope рдореЗрдВ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдПрдХ рдЬрд╛рд╡рд╛ рдмреАрди (рдЗрд╕рдХреЗ рдмрд╛рдж рдмрд╕ рдПрдХ рдмреАрди) рдПрдХ http рдЕрдиреБрд░реЛрдз рдкреНрд░рд╛рдкреНрдд рд╣реЛрдиреЗ рдФрд░ рдЗрд╕ рдЕрдиреБрд░реЛрдз рдХреЗ рдкреВрд░рд╛ рд╣реЛрдиреЗ рдкрд░ рдореБрдХреНрдд рд╣реЛрдиреЗ рдкрд░ рдмрдирд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЬреЗрдИрдИ рдФрд░ рд╕реНрдкреНрд░рд┐рдВрдЧ рдореЗрдВ рдЕрдкрдирд╛ рджрд╛рдпрд░рд╛ рдмрдирд╛рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рд╣реИред рдпрд╛рдиреА рд╣рдо рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдЬреАрд╡рди рдЪрдХреНрд░ рдХреЗ рд╕рд╛рде рд╡рд╕реНрддреБрдУрдВ рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ - рд╡реЗ рд╣рдорд╛рд░реЗ рдХрд┐рд╕реА рднреА рдШрдЯрдирд╛ рджреНрд╡рд╛рд░рд╛ рдмрдирд╛рдП рдЬрд╛рдПрдВрдЧреЗ рдФрд░ рдирд╖реНрдЯ рднреА рд╣реЛрдВрдЧреЗред рдЬреЗрдИрдИ рдореЗрдВ, рд╕реАрдбреАрдЖрдИ (рдкреНрд░рд╕рдВрдЧ рдФрд░ рдирд┐рд░реНрднрд░рддрд╛ рдЗрдВрдЬреЗрдХреНрд╢рди) рд╡рд┐рдирд┐рд░реНрджреЗрд╢ рдЗрд╕рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИ, рдФрд░ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдПрдХ рд╕рдорд╛рди рдирд┐рд░реНрдорд┐рдд рдЧреБрдВрдЬрд╛рдЗрд╢ рд╣реИред рдпрд╣ рдПрдХ рд╡рд╛рд░реНрддрд╛рд▓рд╛рдк рд╣реИред рдмрд╛рддрдЪреАрдд рд╢реБрд░реВ рдХрд░рдиреЗ рдФрд░ рд╕рдорд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдкреАрдЖрдИ рдФрд░ рдПрдиреЛрдЯреЗрд╢рди рд╣реИрдВред рдпрджрд┐ рд╣рдо рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рд╡рд╛рд░реНрддрд╛рд▓рд╛рдкрд╕реНрдХреЛрдк RequestScope рдХреА рддрд░рд╣ рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд░рддрд╛ рд╣реИред рдкреНрд░рддреНрдпреЗрдХ рд╡реНрдпрдХреНрддрд┐рдЧрдд рдХреНрд▓рд╛рдЗрдВрдЯ рдХреА рдмрд╛рддрдЪреАрдд рдХреЛ рдЯреНрд░реИрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдПрдХ рд╡рд┐рд╢реЗрд╖ рдмрд╛рддрдЪреАрдд рдЖрдИрдбреАрдбреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рдЖрдорддреМрд░ рдкрд░ http рдЕрдиреБрд░реЛрдз рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд░реВрдк рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╡реЗрдм рд╕реЗрд╡рд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдФрд░ рд╡рд╕рдВрдд рдореЗрдВ рдРрд╕рд╛ рдХреБрдЫ рднреА рдирд╣реАрдВ рд╣реИред рд▓реЗрдХрд┐рди рдореЗрд░реЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдореЗрдВ, рдЧреНрд░рд╛рд╣рдХ рдиреЗ рдореБрдЭреЗ рдПрдХ рд╡реЗрдм рд╕реЗрд╡рд╛ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╣рд╛ рдЬреЛ рд▓рдЧрд╛рддрд╛рд░ рдХрдИ рдХреЙрд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдмрд╛рд╣рд░реА рд╕рд┐рд╕реНрдЯрдо рдХреЗ рд╕рдорд╛рди рд╢рд╛рд░реАрд░рд┐рдХ рдХрдиреЗрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреА рд╣реИред рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдорд╛рддреНрд░рд╛ рдореЗрдВ рдЕрддрд┐рд░рд┐рдХреНрдд рдбреЗрдЯрд╛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдирд╛ рднреА рдЖрд╡рд╢реНрдпрдХ рдерд╛ред рдпрд╛рдиреА рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдЕрд╡рдзрд┐ рдХреЗ рд▓рд┐рдП рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рд╕реНрдерд┐рддрд┐ (рдПрдХ рдХрдиреЗрдХреНрд╢рди рдФрд░ рдбреЗрдЯрд╛ рдХреЗ рд╕рд╛рде рдПрдХ рд╡рд╕реНрддреБ) рдХреЛ рдмрдЪрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдерд╛, рдПрдХ рд╡реЗрдм рд╕реЗрд╡рд╛ рдХреЗ рд▓рд┐рдП рд╡рд╛рд░реНрддрд╛рд▓рд╛рдк рдЧреБрдВрдЬрд╛рдЗрд╢ рдХрд╛ рдРрд╕рд╛ рдПрдирд╛рд▓реЙрдЧред рдЖрдк рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рдорд╛рд░ рдореЗрдВ рдЗрд╕ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЛ рдмрдЪрд╛ рд╕рдХрддреЗ рд╣реИрдВ, рдЬрд╣рд╛рдВ рдХреБрдВрдЬреА рд╣рдорд╛рд░реА рдПрдирд╛рд▓реЙрдЧ рдмрд╛рддрдЪреАрдд рд╣реЛрдЧреА, рдФрд░ рд╕рд░реНрд╡рд┐рд╕ рд╕рд░реНрд╡рд░ рдореЗрдВ Mar рдбрд╛рд▓ рджреЗрдВ рдФрд░ рдЗрд╕реЗ рд╡реЗрдм рд╕реЗрд╡рд╛ рд╡рд┐рдзрд┐рдпреЛрдВ рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВред рд▓реЗрдХрд┐рди рдпрд╣ рдЕрд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИред рдпрд╣ рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИ рдЬрдм рд╕рд░реНрд╡рд░ рд╕реНрд╡рдпрдВ рд╣рдореЗрдВ рджрд┐рдП рдЧрдП рдмрд╛рддрдЪреАрдд рдХреЗ рдЕрдиреБрд╕рд╛рд░ рд╣рдорд╛рд░реА рд╡рд╕реНрддреБ рдХреЗ рд╕рд╛рде рдЗрдВрдЬреЗрдХреНрдЯ рдХрд░реЗрдЧрд╛ред рдЗрд╕рд▓рд┐рдП, рд╣рдо рдЕрдкрдирд╛ рджрд╛рдпрд░рд╛ рдмрдирд╛рдПрдВрдЧреЗ, рдЬреЛ SOAP рд╡реЗрдм рд╕реЗрд╡рд╛ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░реЗрдЧрд╛ред рд╡реЗрдм рд╕реЗрд╡рд╛ рд╕реНрд╡рдпрдВ рдХрд┐рд╕реА рднреА рджрд╛рдпрд░реЗ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рдирд╣реАрдВ рд╣реЛ рд╕рдХрддреА рд╣реИ, рд▓реЗрдХрд┐рди рд╣рдорд╛рд░реА рд╕реЗрдо, рдЬрд┐рд╕реЗ рд╣рдо рд╡реЗрдм рд╕реЗрд╡рд╛ рдореЗрдВ рдЗрдВрдЬреЗрдХреНрдЯ рдХрд░реЗрдВрдЧреЗ, рд╣рдорд╛рд░реЗ рджрд╛рдпрд░реЗ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рд╣реЛрдЧреАред



рд╕реНрдкреНрд░рд┐рдВрдЧ рдФрд░ рдЬреЗрдИрдИ рдХреЗ рд▓рд┐рдП рдХрд╕реНрдЯрдорд╕реНрдХреЛрдк рдмрдирд╛рдирд╛ рдмрд╣реБрдд рд╕рдорд╛рди рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмрдирд╛рдиреЗ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ: рд╣рдорд╛рд░реА рд╡реЗрдм рд╕реЗрд╡рд╛ рдореЗрдВ рдПрдХ рд╡рд┐рдзрд┐ рд╣реЛрдЧреА рдЬреЛ рд╣рдорд╛рд░реЗ рджрд╛рдпрд░реЗ рдХреЛ рд╕рдХреНрд░рд┐рдп рдХрд░рддреА рд╣реИ рдФрд░ рд╕реЗрд╢рдирдЖрдИрдбреАрдбреА (рдмрд╛рддрдЪреАрдд рдХрд╛ рдПрдирд╛рд▓реЙрдЧ) рджреЗрддреА рд╣реИред рдлрд┐рд░, рдЗрд╕ рдЖрдИрдбреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рд╣рдо рдПрдХ рдРрд╕реА рд╡рд┐рдзрд┐ рдХрд╣реЗрдВрдЧреЗ рдЬреЛ рдбреЗрдЯрд╛ рдХреЛ рд╣рдорд╛рд░реЗ рджрд╛рдпрд░реЗ рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддреА рд╣реИред рдлрд┐рд░ рд╣рдо рдПрдХ рд╡рд┐рдзрд┐ рдХрд╣рддреЗ рд╣реИрдВ рдЬреЛ рдЗрд╕ рдбреЗрдЯрд╛ рдХреЛ рдкрдврд╝рддрд╛ рд╣реИ, рдФрд░ рдлрд┐рд░ рдЧреБрдВрдЬрд╛рдЗрд╢ рдмрдВрдж рдХрд░ рджреЗрддрд╛ рд╣реИред рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рджреЛрдиреЛрдВ рдорд╛рдорд▓реЛрдВ рдореЗрдВ рд╕рдорд╛рди рд╣реИ:

ред

рд╡рд╕рдВрдд рдореЗрдВ, рд╣рдо Apache CXF рдХрд╛ рдЙрдкрдпреЛрдЧ рдПрдХ рд╡реЗрдм рд╕реЗрд╡рд╛ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд░реЗрдВрдЧреЗ рддрд╛рдХрд┐ JEE рд╕реЗ рдиреНрдпреВрдирддрдо рдЕрдВрддрд░ рд╣реЛред



рдПрдХ рд╕реНрдХреЛрдк рд░реЗрдлрд░реЗрдВрд╕ рдХреНрд▓рд╛рд╕ рдмрдирд╛рдирд╛ред



рд╕рдВрджрд░реНрдн рд╣рдорд╛рд░реЗ рджрд╛рдпрд░реЗ рдХреА рдлрд▓рд┐рдпреЛрдВ рдХреЛ рдЙрддреНрдкрдиреНрди / рд╕рдВрдЧреНрд░рд╣реАрдд / рдирд┐рд╖реНрдХреНрд░рд┐рдп рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИред рд╣рдорд╛рд░реЗ рдУрд╕реНрдкреНрд░реЗ рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рд╕рддреНрд░ рдХреЛ рдПрдХ рд╡рд┐рд╢реЗрд╖ рдЖрдИрдбреА рджреНрд╡рд╛рд░рд╛ рдкрд╣рдЪрд╛рдирд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬреЛ рдереНрд░реЗрдбрд▓реЛрдХ рдЪрд░ рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рд╣реЛрддрд╛ рд╣реИред рд╕рдВрджрд░реНрдн рдЗрд╕ рдЖрдИрдбреА рдХреЛ рд╡рд░реНрддрдорд╛рди рд╕рддреНрд░ рдХреЗ рдЕрдиреБрд░реВрдк рд╕реЗрдо рдХреЗ рдЙрджрд╛рд╣рд░рдг рджреЗрддрд╛ рд╣реИ, рдЬреЛ рд╕реНрдерд╛рдиреАрдп рд░реВрдк рд╕реЗ рдорд╛рдирдЪрд┐рддреНрд░ рд╡рд░реНрдЧ рдХреЗ рдСрдмреНрдЬреЗрдХреНрдЯ рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рд╣реЛрддреЗ рд╣реИрдВред рдпрд╛рдиреА рдкреНрд░рддреНрдпреЗрдХ рдереНрд░реЗрдб рд╕реЗрд╢рди рдХрд╛ рдЕрдкрдирд╛ рдорд╛рди рд╣реЛрдЧрд╛ рдФрд░ рд╕рдВрджрд░реНрдн рд╕реЗрдо рдХреЗ рд╕рдВрдмрдВрдзрд┐рдд рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХреЛ рд▓реМрдЯрд╛рдПрдЧрд╛ред рддрджрдиреБрд╕рд╛рд░, рд╕рдВрджрд░реНрдн рдореЗрдВ рдПрдХ рд╕рддреНрд░ рдХреЛ рд╕рдХреНрд░рд┐рдп рдФрд░ рдирд┐рд╖реНрдХреНрд░рд┐рдп рдХрд░рдиреЗ рдХреЗ рддрд░реАрдХреЗ рд╢рд╛рдорд┐рд▓ рд╣реИрдВред рдЕрдм рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗред рдЬреЗрдИрдИ рдореЗрдВ рд╕рдХреНрд░рд┐рдпрдг рдФрд░ рдирд┐рд╖реНрдХреНрд░рд┐рдп рдХрд░рдиреЗ рдХреЗ рддрд░реАрдХреЛрдВ рдХреЗ рдЕрд▓рд╛рд╡рд╛, рд╣рдореЗрдВ рд╡рд╕рдВрдд рдореЗрдВ - javax.enterprise.context.spi.Context



рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред javax.enterprise.context.spi.Context



ред рдпреЗ рдЗрдВрдЯрд░рдлреЗрд╕ рд╕рдорд╛рди рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рднреА рд╕рдорд╛рди рд╣реИрдВред рдЬреЗрдИрдИ рдХреЗ рд▓рд┐рдП, рд╣рдо рд╡рд╕рдВрдд рдХреЗ рд▓рд┐рдП WsContext рдХреНрд▓рд╛рд╕ рдмрдирд╛рдПрдВрдЧреЗ - WsScopeред рдЙрдирдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рднрд╛рдЧ рд╣реЛрддреЗ рд╣реИрдВ:

рдмреАрди рд╕рддреНрд░ рднрдВрдбрд╛рд░рдг


рдЬреЗрдИрдИ рдореЗрдВ:


 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



рдПрдХ рдирдХреНрд╢рд╛ рд╣реИ, рдЬрд╣рд╛рдБ рдХреБрдВрдЬреА рд╕рддреНрд░ рдЖрдИрдбреА рд╣реИ, рдФрд░ рдЗрд╕ рд╕рддреНрд░ рдХрд╛ рдореИрдк рдмрд┐рди рдореВрд▓реНрдп рд╣реИред рд▓реЗрдХрд┐рди рдХреЗрд╡рд▓ рдмрд┐рди рд╕рдВрджрд░реНрднрд┐рдд рдХрд░рдирд╛ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рдирд╣реАрдВ рд╣реИред рд╕реАрдбреАрдЖрдИ рдмрд┐рди рдХреЛ рдирд┐рд╖реНрдХреНрд░рд┐рдп рдХрд░рддреЗ рд╕рдордп, рдЖрдкрдХреЛ рдЙрд╕ рд╕рдВрджрд░реНрдн рдХреЛ рдЬрд╛рдирдирд╛ рд╣реЛрдЧрд╛ рдЬрд┐рд╕рдореЗрдВ рдмрд┐рди рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рдерд╛, рдЗрд╕рд▓рд┐рдП InstanceInfo рд╡рд░реНрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ ctx рд╕рдВрджрд░реНрдн рд╣реИ, рдФрд░ рдЙрджрд╛рд╣рд░рдг рдмрд┐рди рд╣реИред рдмрд┐рди рд╕реЗ рд╢рд╛рджреА рдХрд░рдиреЗ рдХреА рдХреБрдВрдЬреА 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