001
014
015 package com.liferay.portlet;
016
017 import com.liferay.portal.kernel.exception.PortalException;
018 import com.liferay.portal.kernel.exception.SystemException;
019 import com.liferay.portal.kernel.log.Log;
020 import com.liferay.portal.kernel.log.LogFactoryUtil;
021 import com.liferay.portal.kernel.transaction.Propagation;
022 import com.liferay.portal.kernel.transaction.TransactionAttribute;
023 import com.liferay.portal.kernel.transaction.TransactionInvokerUtil;
024 import com.liferay.portal.kernel.util.HashUtil;
025 import com.liferay.portal.kernel.util.StringPool;
026 import com.liferay.portal.kernel.util.Validator;
027 import com.liferay.portal.service.PortalPreferencesLocalServiceUtil;
028 import com.liferay.portal.service.persistence.PortalPreferencesUtil;
029
030 import java.io.IOException;
031 import java.io.Serializable;
032
033 import java.util.Arrays;
034 import java.util.Collections;
035 import java.util.ConcurrentModificationException;
036 import java.util.HashMap;
037 import java.util.Map;
038 import java.util.concurrent.Callable;
039
040 import javax.portlet.ReadOnlyException;
041
042 import org.hibernate.StaleObjectStateException;
043
044
048 public class PortalPreferencesImpl
049 extends BasePreferencesImpl
050 implements Cloneable, PortalPreferences, Serializable {
051
052 public static final TransactionAttribute SUPPORTS_TRANSACTION_ATTRIBUTE;
053
054 static {
055 TransactionAttribute.Builder builder =
056 new TransactionAttribute.Builder();
057
058 builder.setPropagation(Propagation.SUPPORTS);
059 builder.setReadOnly(true);
060 builder.setRollbackForClasses(
061 PortalException.class, SystemException.class);
062
063 SUPPORTS_TRANSACTION_ATTRIBUTE = builder.build();
064 }
065
066 public PortalPreferencesImpl() {
067 this(0, 0, null, Collections.<String, Preference>emptyMap(), false);
068 }
069
070 public PortalPreferencesImpl(
071 com.liferay.portal.model.PortalPreferences portalPreferences,
072 boolean signedIn) {
073
074 this(
075 portalPreferences.getOwnerId(), portalPreferences.getOwnerType(),
076 portalPreferences.getPreferences(),
077 PortletPreferencesFactoryImpl.createPreferencesMap(
078 portalPreferences.getPreferences()),
079 signedIn);
080
081 _portalPreferences = (com.liferay.portal.model.PortalPreferences)
082 portalPreferences.clone();
083 }
084
085 public PortalPreferencesImpl(
086 long ownerId, int ownerType, String xml,
087 Map<String, Preference> preferences, boolean signedIn) {
088
089 super(ownerId, ownerType, xml, preferences);
090
091 _signedIn = signedIn;
092 }
093
094 @Override
095 public PortalPreferencesImpl clone() {
096 if (_portalPreferences == null) {
097 return new PortalPreferencesImpl(
098 getOwnerId(), getOwnerType(), getOriginalXML(),
099 new HashMap<>(getOriginalPreferences()), isSignedIn());
100 }
101
102 return new PortalPreferencesImpl(_portalPreferences, isSignedIn());
103 }
104
105 @Override
106 public boolean equals(Object obj) {
107 if (this == obj) {
108 return true;
109 }
110
111 if (!(obj instanceof PortalPreferencesImpl)) {
112 return false;
113 }
114
115 PortalPreferencesImpl portalPreferences = (PortalPreferencesImpl)obj;
116
117 if ((getOwnerId() == portalPreferences.getOwnerId()) &&
118 (getOwnerType() == portalPreferences.getOwnerType()) &&
119 getPreferences().equals(portalPreferences.getPreferences())) {
120
121 return true;
122 }
123 else {
124 return false;
125 }
126 }
127
128 @Override
129 public long getUserId() {
130 return _userId;
131 }
132
133 @Override
134 public String getValue(String namespace, String key) {
135 return getValue(namespace, key, null);
136 }
137
138 @Override
139 public String getValue(String namespace, String key, String defaultValue) {
140 key = _encodeKey(namespace, key);
141
142 return super.getValue(key, defaultValue);
143 }
144
145 @Override
146 public String[] getValues(String namespace, String key) {
147 return getValues(namespace, key, null);
148 }
149
150 @Override
151 public String[] getValues(
152 String namespace, String key, String[] defaultValue) {
153
154 key = _encodeKey(namespace, key);
155
156 return super.getValues(key, defaultValue);
157 }
158
159 @Override
160 public int hashCode() {
161 int hashCode = HashUtil.hash(0, getOwnerId());
162
163 hashCode = HashUtil.hash(hashCode, getOwnerType());
164 hashCode = HashUtil.hash(hashCode, getPreferences());
165
166 return hashCode;
167 }
168
169 @Override
170 public boolean isSignedIn() {
171 return _signedIn;
172 }
173
174 @Override
175 public void reset(final String key) throws ReadOnlyException {
176 if (isReadOnly(key)) {
177 throw new ReadOnlyException(key);
178 }
179
180 Callable<Void> callable = new Callable<Void>() {
181
182 @Override
183 public Void call() {
184 Map<String, Preference> modifiedPreferences =
185 getModifiedPreferences();
186
187 modifiedPreferences.remove(key);
188
189 return null;
190 }
191 };
192
193 try {
194 retryableStore(callable, key);
195 }
196 catch (ConcurrentModificationException cme) {
197 throw cme;
198 }
199 catch (Throwable t) {
200 _log.error(t, t);
201 }
202 }
203
204 @Override
205 public void resetValues(String namespace) {
206 Map<String, Preference> preferences = getPreferences();
207
208 try {
209 for (Map.Entry<String, Preference> entry : preferences.entrySet()) {
210 String key = entry.getKey();
211
212 if (key.startsWith(namespace) && !isReadOnly(key)) {
213 reset(key);
214 }
215 }
216 }
217 catch (ConcurrentModificationException cme) {
218 throw cme;
219 }
220 catch (Throwable t) {
221 _log.error(t, t);
222 }
223 }
224
225 @Override
226 public void setSignedIn(boolean signedIn) {
227 _signedIn = signedIn;
228 }
229
230 @Override
231 public void setUserId(long userId) {
232 _userId = userId;
233 }
234
235 @Override
236 public void setValue(
237 final String namespace, final String key, final String value) {
238
239 if (Validator.isNull(key) || key.equals(_RANDOM_KEY)) {
240 return;
241 }
242
243 try {
244 Callable<Void> callable = new Callable<Void>() {
245
246 @Override
247 public Void call() throws ReadOnlyException {
248 String encodedKey = _encodeKey(namespace, key);
249
250 if (value != null) {
251 PortalPreferencesImpl.super.setValue(encodedKey, value);
252 }
253 else {
254 reset(encodedKey);
255 }
256
257 return null;
258 }
259
260 };
261
262 if (_signedIn) {
263 retryableStore(callable, _encodeKey(namespace, key));
264 }
265 else {
266 callable.call();
267 }
268 }
269 catch (ConcurrentModificationException cme) {
270 throw cme;
271 }
272 catch (Throwable t) {
273 _log.error(t, t);
274 }
275 }
276
277 @Override
278 public void setValues(
279 final String namespace, final String key, final String[] values) {
280
281 if (Validator.isNull(key) || key.equals(_RANDOM_KEY)) {
282 return;
283 }
284
285 try {
286 Callable<Void> callable = new Callable<Void>() {
287
288 @Override
289 public Void call() throws ReadOnlyException {
290 String encodedKey = _encodeKey(namespace, key);
291
292 if (values != null) {
293 PortalPreferencesImpl.super.setValues(
294 encodedKey, values);
295 }
296 else {
297 reset(encodedKey);
298 }
299
300 return null;
301 }
302
303 };
304
305 if (_signedIn) {
306 retryableStore(callable, _encodeKey(namespace, key));
307 }
308 else {
309 callable.call();
310 }
311 }
312 catch (ConcurrentModificationException cme) {
313 throw cme;
314 }
315 catch (Throwable t) {
316 _log.error(t, t);
317 }
318 }
319
320 @Override
321 public void store() throws IOException {
322 try {
323 if (_portalPreferences == null) {
324 _portalPreferences =
325 PortalPreferencesLocalServiceUtil.updatePreferences(
326 getOwnerId(), getOwnerType(), this);
327 }
328 else {
329 PortalPreferencesWrapperCacheUtil.remove(
330 getOwnerId(), getOwnerType());
331
332 _portalPreferences.setPreferences(toXML());
333
334 PortalPreferencesLocalServiceUtil.updatePortalPreferences(
335 _portalPreferences);
336
337 _portalPreferences = _reload(getOwnerId(), getOwnerType());
338 }
339 }
340 catch (Throwable t) {
341 throw new IOException(t);
342 }
343 }
344
345 protected boolean isCausedByStaleObjectException(Throwable t) {
346 Throwable cause = t.getCause();
347
348 while (t != cause) {
349 if (t instanceof StaleObjectStateException) {
350 return true;
351 }
352
353 if (cause == null) {
354 return false;
355 }
356
357 t = cause;
358
359 cause = t.getCause();
360 }
361
362 return false;
363 }
364
365 protected void retryableStore(Callable<?> callable, String key)
366 throws Throwable {
367
368 String[] originalValues = super.getValues(key, null);
369
370 while (true) {
371 try {
372 callable.call();
373
374 store();
375
376 return;
377 }
378 catch (Exception e) {
379 if (isCausedByStaleObjectException(e)) {
380 long ownerId = getOwnerId();
381 int ownerType = getOwnerType();
382
383 com.liferay.portal.model.PortalPreferences
384 portalPreferences = _reload(ownerId, ownerType);
385
386 if (portalPreferences == null) {
387 continue;
388 }
389
390 PortalPreferencesImpl portalPreferencesImpl =
391 new PortalPreferencesImpl(
392 portalPreferences, isSignedIn());
393
394 if (!Arrays.equals(
395 originalValues,
396 portalPreferencesImpl.getValues(
397 key, (String[])null))) {
398
399 throw new ConcurrentModificationException();
400 }
401
402 reset();
403
404 setOriginalPreferences(
405 portalPreferencesImpl.getOriginalPreferences());
406
407 setOriginalXML(portalPreferences.getPreferences());
408
409 _portalPreferences = portalPreferences;
410 }
411 else {
412 throw e;
413 }
414 }
415 }
416 }
417
418 private String _encodeKey(String namespace, String key) {
419 if (Validator.isNull(namespace)) {
420 return key;
421 }
422 else {
423 return namespace.concat(StringPool.POUND).concat(key);
424 }
425 }
426
427 private com.liferay.portal.model.PortalPreferences _reload(
428 final long ownerId, final int ownerType)
429 throws Throwable {
430
431 return TransactionInvokerUtil.invoke(
432 SUPPORTS_TRANSACTION_ATTRIBUTE,
433 new Callable<com.liferay.portal.model.PortalPreferences>() {
434
435 @Override
436 public com.liferay.portal.model.PortalPreferences call() {
437 return PortalPreferencesUtil.fetchByO_O(
438 ownerId, ownerType, false);
439 }
440
441 });
442 }
443
444 private static final String _RANDOM_KEY = "r";
445
446 private static final Log _log = LogFactoryUtil.getLog(
447 PortalPreferencesImpl.class);
448
449 private com.liferay.portal.model.PortalPreferences _portalPreferences;
450 private boolean _signedIn;
451 private long _userId;
452
453 }