001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portlet.journalcontent.util;
016    
017    import com.liferay.portal.kernel.cache.MultiVMPoolUtil;
018    import com.liferay.portal.kernel.cache.PortalCache;
019    import com.liferay.portal.kernel.cache.index.IndexEncoder;
020    import com.liferay.portal.kernel.cache.index.PortalCacheIndexer;
021    import com.liferay.portal.kernel.cluster.ClusterExecutorUtil;
022    import com.liferay.portal.kernel.cluster.ClusterInvokeThreadLocal;
023    import com.liferay.portal.kernel.cluster.ClusterRequest;
024    import com.liferay.portal.kernel.exception.SystemException;
025    import com.liferay.portal.kernel.lar.ExportImportThreadLocal;
026    import com.liferay.portal.kernel.log.Log;
027    import com.liferay.portal.kernel.log.LogFactoryUtil;
028    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
029    import com.liferay.portal.kernel.util.GetterUtil;
030    import com.liferay.portal.kernel.util.HashUtil;
031    import com.liferay.portal.kernel.util.MethodHandler;
032    import com.liferay.portal.kernel.util.MethodKey;
033    import com.liferay.portal.kernel.util.StringBundler;
034    import com.liferay.portal.kernel.util.StringPool;
035    import com.liferay.portal.kernel.util.StringUtil;
036    import com.liferay.portal.kernel.util.Validator;
037    import com.liferay.portal.model.Layout;
038    import com.liferay.portal.model.LayoutSet;
039    import com.liferay.portal.security.permission.ActionKeys;
040    import com.liferay.portal.theme.ThemeDisplay;
041    import com.liferay.portlet.journal.model.JournalArticleDisplay;
042    import com.liferay.portlet.journal.service.JournalArticleLocalServiceUtil;
043    import com.liferay.portlet.journal.service.permission.JournalArticlePermission;
044    
045    import java.io.Serializable;
046    
047    import java.util.regex.Matcher;
048    import java.util.regex.Pattern;
049    
050    import org.apache.commons.lang.time.StopWatch;
051    
052    /**
053     * @author Brian Wing Shun Chan
054     * @author Raymond Aug??
055     * @author Michael Young
056     */
057    @DoPrivileged
058    public class JournalContentImpl implements JournalContent {
059    
060            @Override
061            public void clearCache() {
062                    if (ExportImportThreadLocal.isImportInProcess()) {
063                            return;
064                    }
065    
066                    _portalCache.removeAll();
067            }
068    
069            @Override
070            public void clearCache(
071                    long groupId, String articleId, String ddmTemplateKey) {
072    
073                    _portalCacheIndexer.removeKeys(
074                            JournalContentKeyIndexEncoder.encode(
075                                    groupId, articleId, ddmTemplateKey));
076    
077                    if (!ClusterInvokeThreadLocal.isEnabled()) {
078                            return;
079                    }
080    
081                    MethodHandler methodHandler = new MethodHandler(
082                            _clearCacheMethodKey, groupId, articleId, ddmTemplateKey);
083    
084                    ClusterRequest clusterRequest = ClusterRequest.createMulticastRequest(
085                            methodHandler, true);
086    
087                    clusterRequest.setFireAndForget(true);
088    
089                    try {
090                            ClusterExecutorUtil.execute(clusterRequest);
091                    }
092                    catch (SystemException se) {
093                            _log.error(se, se);
094                    }
095            }
096    
097            @Override
098            public String getContent(
099                    long groupId, String articleId, String viewMode, String languageId,
100                    String xmlRequest) {
101    
102                    return getContent(
103                            groupId, articleId, null, viewMode, languageId, null, xmlRequest);
104            }
105    
106            @Override
107            public String getContent(
108                    long groupId, String articleId, String ddmTemplateKey, String viewMode,
109                    String languageId, String xmlRequest) {
110    
111                    return getContent(
112                            groupId, articleId, ddmTemplateKey, viewMode, languageId, null,
113                            xmlRequest);
114            }
115    
116            @Override
117            public String getContent(
118                    long groupId, String articleId, String ddmTemplateKey, String viewMode,
119                    String languageId, ThemeDisplay themeDisplay) {
120    
121                    return getContent(
122                            groupId, articleId, ddmTemplateKey, viewMode, languageId,
123                            themeDisplay, null);
124            }
125    
126            @Override
127            public String getContent(
128                    long groupId, String articleId, String ddmTemplateKey, String viewMode,
129                    String languageId, ThemeDisplay themeDisplay, String xmlRequest) {
130    
131                    JournalArticleDisplay articleDisplay = getDisplay(
132                            groupId, articleId, ddmTemplateKey, viewMode, languageId,
133                            themeDisplay, 1, xmlRequest);
134    
135                    if (articleDisplay != null) {
136                            return articleDisplay.getContent();
137                    }
138                    else {
139                            return null;
140                    }
141            }
142    
143            @Override
144            public String getContent(
145                    long groupId, String articleId, String viewMode, String languageId,
146                    ThemeDisplay themeDisplay) {
147    
148                    return getContent(
149                            groupId, articleId, null, viewMode, languageId, themeDisplay);
150            }
151    
152            @Override
153            public JournalArticleDisplay getDisplay(
154                    long groupId, String articleId, double version, String ddmTemplateKey,
155                    String viewMode, String languageId, ThemeDisplay themeDisplay, int page,
156                    String xmlRequest) {
157    
158                    StopWatch stopWatch = new StopWatch();
159    
160                    stopWatch.start();
161    
162                    articleId = StringUtil.toUpperCase(GetterUtil.getString(articleId));
163                    ddmTemplateKey = StringUtil.toUpperCase(
164                            GetterUtil.getString(ddmTemplateKey));
165    
166                    long layoutSetId = 0;
167                    boolean secure = false;
168    
169                    if (themeDisplay != null) {
170                            try {
171                                    if (!JournalArticlePermission.contains(
172                                                    themeDisplay.getPermissionChecker(), groupId, articleId,
173                                                    ActionKeys.VIEW)) {
174    
175                                            return null;
176                                    }
177    
178                                    Layout layout = themeDisplay.getLayout();
179    
180                                    LayoutSet layoutSet = layout.getLayoutSet();
181    
182                                    layoutSetId = layoutSet.getLayoutSetId();
183                            }
184                            catch (Exception e) {
185                            }
186    
187                            secure = themeDisplay.isSecure();
188                    }
189    
190                    JournalContentKey journalContentKey = new JournalContentKey(
191                            groupId, articleId, version, ddmTemplateKey, layoutSetId, viewMode,
192                            languageId, page, secure);
193    
194                    JournalArticleDisplay articleDisplay = _portalCache.get(
195                            journalContentKey);
196    
197                    boolean lifecycleRender = isLifecycleRender(themeDisplay, xmlRequest);
198    
199                    if ((articleDisplay == null) || !lifecycleRender) {
200                            articleDisplay = getArticleDisplay(
201                                    groupId, articleId, ddmTemplateKey, viewMode, languageId, page,
202                                    xmlRequest, themeDisplay);
203    
204                            if ((articleDisplay != null) && articleDisplay.isCacheable() &&
205                                    lifecycleRender) {
206    
207                                    _portalCache.put(journalContentKey, articleDisplay);
208                            }
209                    }
210    
211                    if (_log.isDebugEnabled()) {
212                            _log.debug(
213                                    "getDisplay for {" + groupId + ", " + articleId + ", " +
214                                            ddmTemplateKey + ", " + viewMode + ", " + languageId +
215                                                    ", " + page + "} takes " + stopWatch.getTime() + " ms");
216                    }
217    
218                    return articleDisplay;
219            }
220    
221            @Override
222            public JournalArticleDisplay getDisplay(
223                    long groupId, String articleId, String viewMode, String languageId,
224                    String xmlRequest) {
225    
226                    return getDisplay(
227                            groupId, articleId, null, viewMode, languageId, null, 1,
228                            xmlRequest);
229            }
230    
231            @Override
232            public JournalArticleDisplay getDisplay(
233                    long groupId, String articleId, String ddmTemplateKey, String viewMode,
234                    String languageId, String xmlRequest) {
235    
236                    return getDisplay(
237                            groupId, articleId, ddmTemplateKey, viewMode, languageId, null, 1,
238                            xmlRequest);
239            }
240    
241            @Override
242            public JournalArticleDisplay getDisplay(
243                    long groupId, String articleId, String ddmTemplateKey, String viewMode,
244                    String languageId, ThemeDisplay themeDisplay) {
245    
246                    return getDisplay(
247                            groupId, articleId, ddmTemplateKey, viewMode, languageId,
248                            themeDisplay, 1, null);
249            }
250    
251            @Override
252            public JournalArticleDisplay getDisplay(
253                    long groupId, String articleId, String ddmTemplateKey, String viewMode,
254                    String languageId, ThemeDisplay themeDisplay, int page,
255                    String xmlRequest) {
256    
257                    return getDisplay(
258                            groupId, articleId, 0, ddmTemplateKey, viewMode, languageId,
259                            themeDisplay, 1, xmlRequest);
260            }
261    
262            @Override
263            public JournalArticleDisplay getDisplay(
264                    long groupId, String articleId, String viewMode, String languageId,
265                    ThemeDisplay themeDisplay) {
266    
267                    return getDisplay(
268                            groupId, articleId, viewMode, languageId, themeDisplay, 1);
269            }
270    
271            @Override
272            public JournalArticleDisplay getDisplay(
273                    long groupId, String articleId, String viewMode, String languageId,
274                    ThemeDisplay themeDisplay, int page) {
275    
276                    return getDisplay(
277                            groupId, articleId, null, viewMode, languageId, themeDisplay, page,
278                            null);
279            }
280    
281            protected JournalArticleDisplay getArticleDisplay(
282                    long groupId, String articleId, String ddmTemplateKey, String viewMode,
283                    String languageId, int page, String xmlRequest,
284                    ThemeDisplay themeDisplay) {
285    
286                    try {
287                            if (_log.isInfoEnabled()) {
288                                    _log.info(
289                                            "Get article display {" + groupId + ", " + articleId +
290                                                    ", " + ddmTemplateKey + "}");
291                            }
292    
293                            return JournalArticleLocalServiceUtil.getArticleDisplay(
294                                    groupId, articleId, ddmTemplateKey, viewMode, languageId, page,
295                                    xmlRequest, themeDisplay);
296                    }
297                    catch (Exception e) {
298                            if (_log.isWarnEnabled()) {
299                                    _log.warn(
300                                            "Unable to get display for " + groupId + " " +
301                                                    articleId + " " + languageId);
302                            }
303    
304                            return null;
305                    }
306            }
307    
308            protected boolean isLifecycleRender(
309                    ThemeDisplay themeDisplay, String xmlRequest) {
310    
311                    if (themeDisplay != null) {
312                            return themeDisplay.isLifecycleRender();
313                    }
314                    else if (Validator.isNotNull(xmlRequest)) {
315                            Matcher matcher = lifecycleRenderPhasePattern.matcher(xmlRequest);
316    
317                            return matcher.find();
318                    }
319                    else {
320                            return false;
321                    }
322            }
323    
324            protected static final String CACHE_NAME = JournalContent.class.getName();
325    
326            protected static Pattern lifecycleRenderPhasePattern = Pattern.compile(
327                    "<lifecycle>\\s*RENDER_PHASE\\s*</lifecycle>");
328    
329            private static final IndexEncoder<String, JournalContentKey> _indexEncoder =
330                    new JournalContentKeyIndexEncoder();
331            private static final PortalCache<JournalContentKey, JournalArticleDisplay>
332                    _portalCache = MultiVMPoolUtil.getCache(CACHE_NAME);
333            private static final PortalCacheIndexer
334                    <String, JournalContentKey, JournalArticleDisplay> _portalCacheIndexer =
335                            new PortalCacheIndexer
336                                    <String, JournalContentKey, JournalArticleDisplay> (
337                                            _indexEncoder, _portalCache);
338    
339            private static Log _log = LogFactoryUtil.getLog(JournalContentImpl.class);
340    
341            private static final MethodKey _clearCacheMethodKey = new MethodKey(
342                    JournalContentUtil.class,
343                            "clearCache", long.class, String.class, String.class);
344    
345            private static class JournalContentKey implements Serializable {
346    
347                    @Override
348                    public boolean equals(Object obj) {
349                            JournalContentKey journalContentKey = (JournalContentKey)obj;
350    
351                            if ((journalContentKey._groupId == _groupId) &&
352                                    Validator.equals(journalContentKey._articleId, _articleId) &&
353                                    (journalContentKey._version == _version) &&
354                                    Validator.equals(
355                                            journalContentKey._ddmTemplateKey, _ddmTemplateKey) &&
356                                    (journalContentKey._layoutSetId == _layoutSetId) &&
357                                    Validator.equals(journalContentKey._viewMode, _viewMode) &&
358                                    Validator.equals(journalContentKey._languageId, _languageId) &&
359                                    (journalContentKey._page == _page) &&
360                                    (journalContentKey._secure == _secure)) {
361    
362                                    return true;
363                            }
364    
365                            return false;
366                    }
367    
368                    @Override
369                    public int hashCode() {
370                            int hashCode = HashUtil.hash(0, _groupId);
371    
372                            hashCode = HashUtil.hash(hashCode, _articleId);
373                            hashCode = HashUtil.hash(hashCode, _version);
374                            hashCode = HashUtil.hash(hashCode, _ddmTemplateKey);
375                            hashCode = HashUtil.hash(hashCode, _layoutSetId);
376                            hashCode = HashUtil.hash(hashCode, _viewMode);
377                            hashCode = HashUtil.hash(hashCode, _languageId);
378                            hashCode = HashUtil.hash(hashCode, _page);
379    
380                            return HashUtil.hash(hashCode, _secure);
381                    }
382    
383                    private JournalContentKey(
384                            long groupId, String articleId, double version,
385                            String ddmTemplateKey, long layoutSetId, String viewMode,
386                            String languageId, int page, boolean secure) {
387    
388                            _groupId = groupId;
389                            _articleId = articleId;
390                            _version = version;
391                            _ddmTemplateKey = ddmTemplateKey;
392                            _layoutSetId = layoutSetId;
393                            _viewMode = viewMode;
394                            _languageId = languageId;
395                            _page = page;
396                            _secure = secure;
397                    }
398    
399                    private static final long serialVersionUID = 1L;
400    
401                    private final String _articleId;
402                    private final String _ddmTemplateKey;
403                    private final long _groupId;
404                    private final String _languageId;
405                    private final long _layoutSetId;
406                    private final int _page;
407                    private final boolean _secure;
408                    private final double _version;
409                    private final String _viewMode;
410    
411            }
412    
413            private static class JournalContentKeyIndexEncoder
414                    implements IndexEncoder<String, JournalContentKey> {
415    
416                    public static String encode(
417                            long groupId, String articleId, String ddmTemplateKey) {
418    
419                            StringBundler sb = new StringBundler(5);
420    
421                            sb.append(groupId);
422                            sb.append(StringPool.UNDERLINE);
423                            sb.append(articleId);
424                            sb.append(StringPool.UNDERLINE);
425                            sb.append(ddmTemplateKey);
426    
427                            return sb.toString();
428                    }
429    
430                    @Override
431                    public String encode(JournalContentKey key) {
432                            return encode(key._groupId, key._articleId, key._ddmTemplateKey);
433                    }
434    
435            }
436    
437    }