Class | Line # | Actions | |||||
---|---|---|---|---|---|---|---|
XWikiContextCopier | 51 | 11 | 0% | 3 | 0 |
1 | /* | |
2 | * See the NOTICE file distributed with this work for additional | |
3 | * information regarding copyright ownership. | |
4 | * | |
5 | * This is free software; you can redistribute it and/or modify it | |
6 | * under the terms of the GNU Lesser General Public License as | |
7 | * published by the Free Software Foundation; either version 2.1 of | |
8 | * the License, or (at your option) any later version. | |
9 | * | |
10 | * This software is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * Lesser General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU Lesser General Public | |
16 | * License along with this software; if not, write to the Free | |
17 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |
18 | * 02110-1301 USA, or see the FSF site: http://www.fsf.org. | |
19 | */ | |
20 | package org.xwiki.mail.internal.thread.context; | |
21 | ||
22 | import java.net.URL; | |
23 | ||
24 | import javax.inject.Inject; | |
25 | import javax.inject.Singleton; | |
26 | ||
27 | import org.xwiki.component.annotation.Component; | |
28 | ||
29 | import com.xpn.xwiki.XWikiContext; | |
30 | import com.xpn.xwiki.web.XWikiRequest; | |
31 | import com.xpn.xwiki.web.XWikiResponse; | |
32 | import com.xpn.xwiki.web.XWikiServletResponseStub; | |
33 | import com.xpn.xwiki.web.XWikiURLFactory; | |
34 | ||
35 | /** | |
36 | * Additionally to using {@link XWikiContext#clone()}, this implementation also tries to make sure that the cloned | |
37 | * context is usable in a different thread. To do this, the request and the response are stubbed, the URL factory is | |
38 | * reinitialized and the store session/transaction are cleared. This latter point is sensible since there is currently | |
39 | * no way to clear the session/transaction only in the copied context. So the session/transaction is cleared in the | |
40 | * original context before cloning, causing a side effect on the original context. You should never copy a context | |
41 | * while a create/update transaction is in progress, since some changes would get rollbacked. | |
42 | * <p> | |
43 | * Note: The clone is still rather shallow, since many fields will still be shared with the original | |
44 | * {@link XWikiContext}. | |
45 | * | |
46 | * @version $Id: fbb5f2d90c586d8af53162d9d1528493b229f9f2 $ | |
47 | * @since 7.1M2 | |
48 | */ | |
49 | @Component | |
50 | @Singleton | |
51 | public class XWikiContextCopier implements Copier<XWikiContext> | |
52 | { | |
53 | @Inject | |
54 | private Copier<XWikiRequest> xwikiRequestCloner; | |
55 | ||
56 | /** | |
57 | * {@inheritDoc} | |
58 | * | |
59 | * Any in progress session/transaction on the store retained by the original context will be closed/rollbacked | |
60 | * prior cloning (see {@link com.xpn.xwiki.store.XWikiStoreInterface#cleanUp(XWikiContext)}). Therefore, | |
61 | * the copy operation has a side effect on the original context. You should never copy a context | |
62 | * while a create/update transaction is in progress, since some changes would get rollbacked. | |
63 | */ | |
64 | 35 | @Override |
65 | public XWikiContext copy(XWikiContext originalXWikiContext) | |
66 | { | |
67 | // Clean up the store session/transaction before cloning. For the hibernate store, in progress | |
68 | // session/transaction is stored in the context, and would be swallow copied when the context is cloned. | |
69 | // Cleaning after clone would not help, since it would close/rollback the session/transaction still referenced | |
70 | // in the original context as well, causing this context to be corrupted. | |
71 | // The correct way would be to not shallow clone the session/transaction when cloning the original context, | |
72 | // since session/transaction are lazy initialize on request when missing. | |
73 | 35 | originalXWikiContext.getWiki().getStore().cleanUp(originalXWikiContext); |
74 | ||
75 | // This is still a shallow clone, but at least for stuff like wikiID and userReference it gets the job done. | |
76 | 35 | XWikiContext clonedXWikiContext = originalXWikiContext.clone(); |
77 | ||
78 | // lets now build the stub context | |
79 | ||
80 | // Copy the request from the context. | |
81 | 35 | clonedXWikiContext.setRequest(this.xwikiRequestCloner.copy(originalXWikiContext.getRequest())); |
82 | ||
83 | // Force forged context response to a stub response, since the current context response | |
84 | // will not mean anything anymore when running in the scheduler's thread, and can cause | |
85 | // errors. | |
86 | 35 | XWikiResponse stub = new XWikiServletResponseStub(); |
87 | 35 | clonedXWikiContext.setResponse(stub); |
88 | ||
89 | // feed the dummy context | |
90 | 35 | if (clonedXWikiContext.getURL() == null) { |
91 | 1 | try { |
92 | 1 | clonedXWikiContext.setURL(new URL("http://www.mystuburl.com/")); |
93 | } catch (Exception e) { | |
94 | // the URL is clearly well formed | |
95 | } | |
96 | } | |
97 | ||
98 | 35 | XWikiURLFactory xurf = |
99 | originalXWikiContext.getWiki().getURLFactoryService() | |
100 | .createURLFactory(originalXWikiContext.getMode(), originalXWikiContext); | |
101 | 35 | clonedXWikiContext.setURLFactory(xurf); |
102 | ||
103 | 35 | return clonedXWikiContext; |
104 | } | |
105 | } |