Wiki source code of Saving Data
Last modified by Vincent Massol on 2024/09/09
Show last authors
author | version | line-number | content |
---|---|---|---|
1 | {{box cssClass="floatinginfobox" title="**Contents**"}} | ||
2 | {{toc/}} | ||
3 | {{/box}} | ||
4 | |||
5 | There are times when you wish to save data. The XWiki platform offers various places that you can use depending on your needs. Here's a rundown of all the options you have. | ||
6 | |||
7 | = Transient Saves = | ||
8 | |||
9 | == Execution Context == | ||
10 | |||
11 | If the data to be saved should only be saved for the duration of a request (i.e. a call to an XWiki URL) then you should declare a property in the **Execution Context**. | ||
12 | |||
13 | For example, from Java in a Component: | ||
14 | |||
15 | {{code language="java"}} | ||
16 | import org.xwiki.execution.*; | ||
17 | |||
18 | @Inject Execution execution; | ||
19 | ... | ||
20 | // Declaring | ||
21 | ExecutionContext ec = execution.getContext(); | ||
22 | ec.newProperty("mykey").initial(initialValue).declare(); | ||
23 | ... | ||
24 | // Updating | ||
25 | ec.setProperty("mykey", newValue); | ||
26 | ... | ||
27 | // Retrieving | ||
28 | Object myvalue = e.getProperty("mykey"); | ||
29 | {{/code}} | ||
30 | |||
31 | === Execution Context Property Declaration === | ||
32 | |||
33 | The declaration is currently optional, the property will be implicitly declared when set the first time. The declaration can be made in an ##ExecutionContextInitializer## component. The initialize method of all such components that are available in the classpath and have been specified in a ##components.txt## file will be called when the execution context is first initialized during the request. | ||
34 | |||
35 | {{code language="java"}} | ||
36 | import org.xwiki.context.ExecutionContext; | ||
37 | import org.xwiki.context.ExecutionContextInitializer; | ||
38 | import org.xwiki.context.ExecutionContextException; | ||
39 | import org.xwiki.component.annotation.Component; | ||
40 | |||
41 | @Component | ||
42 | public class DeclareMyPropertyExecutionContextInitializer implements ExecutionContextInitializer | ||
43 | { | ||
44 | @Override | ||
45 | public void initialize(ExecutionContext executionContext) | ||
46 | { | ||
47 | if (!executionContext.hasProperty("mykey")) { | ||
48 | executionContext.newProperty("mykey").type(String.class).nonNull().initial("").declare(); | ||
49 | } | ||
50 | } | ||
51 | } | ||
52 | {{/code}} | ||
53 | |||
54 | In the above example you can see that it is possible to set various attributes on the property when it is beeing declared. The attributes currently supported are listed in the table below. | ||
55 | |||
56 | During a request cycle, some components may activate a //clean// or a //cloned// execution context by pushing to the execution context stack. You can control how you want your property to be managed in these situations by setting attributes. | ||
57 | |||
58 | |=(% style="width:25%" %)Attribute |=Parameters |=Description | ||
59 | |cloneValue()| - |Indicate that you want the value to be cloned when the execution context is cloned or when your property is inherited from a parent execution context | ||
60 | |makeFinal()| - |Indicate that an exception should be thrown if someone tries to replace the initial value object | ||
61 | |inherited()| - |Indicate that the property should be inherited by any new execution context that is pushed within the current request | ||
62 | |nonNull()| - |Indicate that an exception should be thrown if ##null## is set as the property value | ||
63 | |type(Class<?> type)|((( | ||
64 | ; type | ||
65 | : the class that the value object should be typechecked against | ||
66 | )))|Set a type for performing typechecking when updating the value object. | ||
67 | |||
68 | === Wiki Page Access to Execution Context === | ||
69 | |||
70 | {{info}} | ||
71 | We currently [[cannot access easily the Execution Context from a wiki page>>https://jira.xwiki.org/browse/XCOMMONS-242]] but this should be improved. Currently it's not available from Velocity, but it is from Groovy. | ||
72 | {{/info}} | ||
73 | |||
74 | From a wiki page: | ||
75 | |||
76 | {{code}} | ||
77 | {{groovy}} | ||
78 | import org.xwiki.context.* | ||
79 | |||
80 | def ec = services.component.getInstance(Execution.class).getContext() | ||
81 | ec.setProperty("mykey", myvalue) | ||
82 | {{/groovy}} | ||
83 | {{/code}} | ||
84 | |||
85 | {{info}} | ||
86 | From a wiki page it's much easier to use the older **XWiki Context** (which is supposed to be fully replaced by the Execution Context at some point in the future). | ||
87 | {{/info}} | ||
88 | |||
89 | For example: | ||
90 | |||
91 | {{code}} | ||
92 | {{velocity}} | ||
93 | $xcontext.put("mykey", value) | ||
94 | {{/velocity}} | ||
95 | {{/code}} | ||
96 | |||
97 | {{warning}} | ||
98 | This requires Programming Rights. | ||
99 | {{/warning}} | ||
100 | |||
101 | {{info}} | ||
102 | It's also possible to save data in the HTTP Request even though it's recommended to use the Execution Context instead (since the Execution Context is independent of the execution environment and will work everywhere: Servlets, Portlets, JavaSE, etc). | ||
103 | {{/info}} | ||
104 | |||
105 | For example from Velocity in a wiki page: | ||
106 | |||
107 | {{code}} | ||
108 | {{velocity}} | ||
109 | $request.setAttribute("mykey", value) | ||
110 | {{/velocity}} | ||
111 | {{/code}} | ||
112 | |||
113 | == Servlet Session == | ||
114 | |||
115 | If the data should last a little longer (i.e. for example span more than 1 request), you could save it in the Servlet Session (note that in this case your code will only work in a Servlet Environment). | ||
116 | |||
117 | For example, from Java in a Component: | ||
118 | |||
119 | {{code language="java"}} | ||
120 | import org.xwiki.container.*; | ||
121 | |||
122 | @Inject Container container; | ||
123 | ... | ||
124 | Request request = container.getRequest(); | ||
125 | // Note that this is a bit of a hack and the notion of Session exists in the Container class (getSession()) but the Session interface is empty at the moment, making it useless) | ||
126 | if (request instanceof ServletRequest) { | ||
127 | HttpServletRequest servletRequest = (ServletRequest) request; | ||
128 | HttpSession session = servletRequest.getSession(); | ||
129 | session.setAttribute("mykey", myvalue); | ||
130 | } | ||
131 | {{/code}} | ||
132 | |||
133 | Example from a wiki page: | ||
134 | |||
135 | {{code}} | ||
136 | {{velocity}} | ||
137 | $request.getSession().setAttribute("mykey", myvalue) | ||
138 | {{/velocity}} | ||
139 | {{/code}} | ||
140 | |||
141 | == Temporary Directory == | ||
142 | |||
143 | If the data should last even a little longer than a session, you could save it in a file in the environment's temporary directory. | ||
144 | |||
145 | For example, from Java in a Component: | ||
146 | |||
147 | {{code language="java"}} | ||
148 | import org.xwiki.environment.*; | ||
149 | import org.apache.commons.io.*; | ||
150 | |||
151 | @Inject Environment environment; | ||
152 | ... | ||
153 | File tmpDir = environment.getTemporaryDirectory(); | ||
154 | FileUtils.write(tmpDir, "something"); | ||
155 | {{/code}} | ||
156 | |||
157 | == Servlet Context == | ||
158 | |||
159 | If the Data should last as long as the web application is up, you could use the Servlet Context. It's not very easy to access it but it's possible (note that in this case your code will only work in a Servlet Environment). | ||
160 | |||
161 | For example, from Java in a Component: | ||
162 | |||
163 | {{code language="java"}} | ||
164 | import org.xwiki.container.*; | ||
165 | import com.xpn.xwiki.*; | ||
166 | import com.xpn.xwiki.web.*; | ||
167 | |||
168 | @Inject Execution execution; | ||
169 | ... | ||
170 | // Get the older XWiki Context | ||
171 | XWikiContext xc = (XWikiContext) execution.getContext().getProperty("xwikicontext"); | ||
172 | XWikiEngineContext ec = xc.getEngineContext(); | ||
173 | ec.setAttribute("mykey", myvalue); | ||
174 | {{/code}} | ||
175 | |||
176 | == Using the Cache API == | ||
177 | |||
178 | You can also create a Cache and store data in it. See the [[Cache API>>extensions:Extension.Cache Module]]. | ||
179 | |||
180 | = Permanent Saves = | ||
181 | |||
182 | == Wiki Model == | ||
183 | |||
184 | The best place to save data is usually in the wiki itself (See the [[Data Model>>xwiki:Documentation.DevGuide.DataModel]] and the [[API Guide>>xwiki:Documentation.DevGuide.APIGuide]] for some examples). There are several places where you can store data in the model: | ||
185 | |||
186 | * In the document content itself | ||
187 | * In an XObject attached to a document | ||
188 | * In an attachment | ||
189 | |||
190 | == Permanent Directory == | ||
191 | |||
192 | Another possibility is to use the environment's permanent directory. | ||
193 | |||
194 | For example, from Java in a Component: | ||
195 | |||
196 | {{code language="java"}} | ||
197 | import org.xwiki.environment.*; | ||
198 | import org.apache.commons.io.*; | ||
199 | |||
200 | @Inject Environment environment; | ||
201 | ... | ||
202 | File permDir = environment.getPermanentDirectory(); | ||
203 | FileUtils.write(permDir, "something"); | ||
204 | {{/code}} |