001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.security.permission;
016    
017    import com.liferay.portal.kernel.bean.BeanReference;
018    import com.liferay.portal.kernel.exception.NoSuchResourceActionException;
019    import com.liferay.portal.kernel.exception.ResourceActionsException;
020    import com.liferay.portal.kernel.language.LanguageUtil;
021    import com.liferay.portal.kernel.log.Log;
022    import com.liferay.portal.kernel.log.LogFactoryUtil;
023    import com.liferay.portal.kernel.model.Group;
024    import com.liferay.portal.kernel.model.Organization;
025    import com.liferay.portal.kernel.model.Portlet;
026    import com.liferay.portal.kernel.model.PortletConstants;
027    import com.liferay.portal.kernel.model.ResourceAction;
028    import com.liferay.portal.kernel.model.Role;
029    import com.liferay.portal.kernel.model.RoleConstants;
030    import com.liferay.portal.kernel.model.User;
031    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
032    import com.liferay.portal.kernel.security.permission.ActionKeys;
033    import com.liferay.portal.kernel.security.permission.ModelResourceActionsBag;
034    import com.liferay.portal.kernel.security.permission.PortletResourceActionsBag;
035    import com.liferay.portal.kernel.security.permission.ResourceActions;
036    import com.liferay.portal.kernel.service.GroupServiceUtil;
037    import com.liferay.portal.kernel.service.PortletLocalService;
038    import com.liferay.portal.kernel.service.ResourceActionLocalService;
039    import com.liferay.portal.kernel.service.RoleLocalService;
040    import com.liferay.portal.kernel.util.CharPool;
041    import com.liferay.portal.kernel.util.ContentTypes;
042    import com.liferay.portal.kernel.util.GetterUtil;
043    import com.liferay.portal.kernel.util.ListUtil;
044    import com.liferay.portal.kernel.util.LocaleUtil;
045    import com.liferay.portal.kernel.util.PortletKeys;
046    import com.liferay.portal.kernel.util.ResourceBundleUtil;
047    import com.liferay.portal.kernel.util.StringBundler;
048    import com.liferay.portal.kernel.util.StringPool;
049    import com.liferay.portal.kernel.util.StringUtil;
050    import com.liferay.portal.kernel.util.Validator;
051    import com.liferay.portal.kernel.xml.Document;
052    import com.liferay.portal.kernel.xml.DocumentType;
053    import com.liferay.portal.kernel.xml.Element;
054    import com.liferay.portal.kernel.xml.UnsecureSAXReaderUtil;
055    import com.liferay.portal.util.PropsValues;
056    import com.liferay.registry.collections.ServiceTrackerCollections;
057    import com.liferay.registry.collections.ServiceTrackerMap;
058    import com.liferay.util.JS;
059    
060    import java.io.InputStream;
061    
062    import java.util.ArrayList;
063    import java.util.Collections;
064    import java.util.HashMap;
065    import java.util.HashSet;
066    import java.util.Iterator;
067    import java.util.LinkedHashSet;
068    import java.util.List;
069    import java.util.Locale;
070    import java.util.Map;
071    import java.util.ResourceBundle;
072    import java.util.Set;
073    
074    import javax.servlet.http.HttpServletRequest;
075    
076    import org.apache.struts.util.RequestUtils;
077    
078    /**
079     * @author Brian Wing Shun Chan
080     * @author Daeyoung Song
081     * @author Raymond Augé
082     */
083    @DoPrivileged
084    public class ResourceActionsImpl implements ResourceActions {
085    
086            public ResourceActionsImpl() {
087                    _resourceBundles = ServiceTrackerCollections.openMultiValueMap(
088                            ResourceBundle.class, "language.id");
089            }
090    
091            public void afterPropertiesSet() {
092                    _portletResourceActionsBags = new HashMap<>();
093                    _modelResourceActionsBags = new HashMap<>();
094    
095                    try {
096                            ClassLoader classLoader = getClass().getClassLoader();
097    
098                            for (String config : PropsValues.RESOURCE_ACTIONS_CONFIGS) {
099                                    read(null, classLoader, config);
100                            }
101                    }
102                    catch (Exception e) {
103                            _log.error(e, e);
104                    }
105            }
106    
107            @Override
108            public void checkAction(String name, String actionId)
109                    throws NoSuchResourceActionException {
110    
111                    List<String> resourceActions = getResourceActions(name);
112    
113                    if (!resourceActions.contains(actionId)) {
114                            throw new NoSuchResourceActionException(
115                                    name.concat(StringPool.POUND).concat(actionId));
116                    }
117            }
118    
119            public void destroy() {
120                    _resourceBundles.close();
121            }
122    
123            @Override
124            public String getAction(HttpServletRequest request, String action) {
125                    String key = getActionNamePrefix() + action;
126    
127                    String value = LanguageUtil.get(request, key, null);
128    
129                    if ((value == null) || value.equals(key)) {
130                            value = getResourceBundlesString(request, key);
131                    }
132    
133                    if (value == null) {
134                            value = key;
135                    }
136    
137                    return value;
138            }
139    
140            @Override
141            public String getAction(Locale locale, String action) {
142                    String key = getActionNamePrefix() + action;
143    
144                    String value = LanguageUtil.get(locale, key, null);
145    
146                    if ((value == null) || value.equals(key)) {
147                            value = getResourceBundlesString(locale, key);
148                    }
149    
150                    if (value == null) {
151                            value = key;
152                    }
153    
154                    return value;
155            }
156    
157            @Override
158            public String getActionNamePrefix() {
159                    return _ACTION_NAME_PREFIX;
160            }
161    
162            /**
163             * @deprecated As of 7.0.0
164             */
165            @Deprecated
166            @Override
167            public List<String> getActionsNames(
168                    HttpServletRequest request, List<String> actions) {
169    
170                    Set<String> actionNames = new LinkedHashSet<>();
171    
172                    for (String action : actions) {
173                            actionNames.add(getAction(request, action));
174                    }
175    
176                    return new ArrayList<>(actionNames);
177            }
178    
179            /**
180             * @deprecated As of 7.0.0
181             */
182            @Deprecated
183            @Override
184            public List<String> getActionsNames(
185                    HttpServletRequest request, String name, long actionIds) {
186    
187                    try {
188                            List<ResourceAction> resourceActions =
189                                    resourceActionLocalService.getResourceActions(name);
190    
191                            List<String> actions = new ArrayList<>();
192    
193                            for (ResourceAction resourceAction : resourceActions) {
194                                    long bitwiseValue = resourceAction.getBitwiseValue();
195    
196                                    if ((actionIds & bitwiseValue) == bitwiseValue) {
197                                            actions.add(resourceAction.getActionId());
198                                    }
199                            }
200    
201                            return getActionsNames(request, actions);
202                    }
203                    catch (Exception e) {
204                            _log.error(e, e);
205    
206                            return Collections.emptyList();
207                    }
208            }
209    
210            @Override
211            public String getCompositeModelNameSeparator() {
212                    return _COMPOSITE_MODEL_NAME_SEPARATOR;
213            }
214    
215            @Override
216            public List<String> getModelNames() {
217                    return ListUtil.fromMapKeys(_modelResourceActionsBags);
218            }
219    
220            @Override
221            public List<String> getModelPortletResources(String name) {
222                    ModelResourceActionsBag modelResourceActionsBag =
223                            getModelResourceActionsBag(name);
224    
225                    return new ArrayList<>(modelResourceActionsBag.getResources());
226            }
227    
228            @Override
229            public String getModelResource(HttpServletRequest request, String name) {
230                    String key = getModelResourceNamePrefix() + name;
231    
232                    String value = LanguageUtil.get(request, key, null);
233    
234                    if ((value == null) || value.equals(key)) {
235                            value = getResourceBundlesString(request, key);
236                    }
237    
238                    if (value == null) {
239                            value = key;
240                    }
241    
242                    return value;
243            }
244    
245            @Override
246            public String getModelResource(Locale locale, String name) {
247                    String key = getModelResourceNamePrefix() + name;
248    
249                    String value = LanguageUtil.get(locale, key, null);
250    
251                    if ((value == null) || value.equals(key)) {
252                            value = getResourceBundlesString(locale, key);
253                    }
254    
255                    if (value == null) {
256                            value = key;
257                    }
258    
259                    return value;
260            }
261    
262            @Override
263            public List<String> getModelResourceActions(String name) {
264                    ModelResourceActionsBag modelResourceActionsBag =
265                            getModelResourceActionsBag(name);
266    
267                    return new ArrayList<>(modelResourceActionsBag.getResourceActions());
268            }
269    
270            @Override
271            public List<String> getModelResourceGroupDefaultActions(String name) {
272                    ModelResourceActionsBag modelResourceActionsBag =
273                            getModelResourceActionsBag(name);
274    
275                    return new ArrayList<>(
276                            modelResourceActionsBag.getResourceGroupDefaultActions());
277            }
278    
279            @Override
280            public List<String> getModelResourceGuestDefaultActions(String name) {
281                    ModelResourceActionsBag modelResourceActionsBag =
282                            getModelResourceActionsBag(name);
283    
284                    return new ArrayList<>(
285                            modelResourceActionsBag.getResourceGuestDefaultActions());
286            }
287    
288            @Override
289            public List<String> getModelResourceGuestUnsupportedActions(String name) {
290                    ModelResourceActionsBag modelResourceActionsBag =
291                            getModelResourceActionsBag(name);
292    
293                    return new ArrayList<>(
294                            modelResourceActionsBag.getResourceGuestUnsupportedActions());
295            }
296    
297            @Override
298            public String getModelResourceNamePrefix() {
299                    return _MODEL_RESOURCE_NAME_PREFIX;
300            }
301    
302            @Override
303            public List<String> getModelResourceOwnerDefaultActions(String name) {
304                    ModelResourceActionsBag modelResourceActionsBag =
305                            getModelResourceActionsBag(name);
306    
307                    return new ArrayList<>(
308                            modelResourceActionsBag.getResourceOwnerDefaultActions());
309            }
310    
311            @Override
312            public Double getModelResourceWeight(String name) {
313                    ModelResourceActionsBag modelResourceActionsBag =
314                            getModelResourceActionsBag(name);
315    
316                    Map<String, Double> modelResourceWeights =
317                            modelResourceActionsBag.getResourceWeights();
318    
319                    return modelResourceWeights.get(name);
320            }
321    
322            @Override
323            public String[] getOrganizationModelResources() {
324                    return _organizationModelResources.toArray(
325                            new String[_organizationModelResources.size()]);
326            }
327    
328            @Override
329            public String[] getPortalModelResources() {
330                    return _portalModelResources.toArray(
331                            new String[_portalModelResources.size()]);
332            }
333    
334            @Override
335            public String getPortletBaseResource(String portletName) {
336                    List<String> modelNames = getPortletModelResources(portletName);
337    
338                    for (String modelName : modelNames) {
339                            if (!modelName.contains(".model.")) {
340                                    return modelName;
341                            }
342                    }
343    
344                    return null;
345            }
346    
347            @Override
348            public List<String> getPortletModelResources(String portletName) {
349                    portletName = PortletConstants.getRootPortletId(portletName);
350    
351                    PortletResourceActionsBag portletResourceActionsBag =
352                            getPortletResourceActionsBag(portletName);
353    
354                    Set<String> resources = portletResourceActionsBag.getResources();
355    
356                    if (resources == null) {
357                            return new ArrayList<>();
358                    }
359                    else {
360                            return new ArrayList<>(resources);
361                    }
362            }
363    
364            @Override
365            public List<String> getPortletNames() {
366                    return ListUtil.fromMapKeys(_portletResourceActionsBags);
367            }
368    
369            @Override
370            public List<String> getPortletResourceActions(Portlet portlet) {
371                    Set<String> actions = new LinkedHashSet<>(
372                            getPortletResourceActions(portlet.getPortletId()));
373    
374                    synchronized (this) {
375                            checkPortletActions(portlet, actions);
376                    }
377    
378                    return new ArrayList<>(actions);
379            }
380    
381            @Override
382            public List<String> getPortletResourceActions(String name) {
383                    name = PortletConstants.getRootPortletId(name);
384    
385                    PortletResourceActionsBag portletResourceActionsBag =
386                            getPortletResourceActionsBag(name);
387    
388                    Set<String> actions = portletResourceActionsBag.getResourceActions();
389    
390                    if (!actions.isEmpty()) {
391                            return new ArrayList<>(actions);
392                    }
393    
394                    synchronized (this) {
395                            actions = getPortletMimeTypeActions(name);
396    
397                            if (!name.equals(PortletKeys.PORTAL)) {
398                                    checkPortletActions(name, actions);
399                            }
400    
401                            Set<String> groupDefaultActions =
402                                    portletResourceActionsBag.getResourceGroupDefaultActions();
403    
404                            checkPortletGroupDefaultActions(groupDefaultActions);
405    
406                            Set<String> guestDefaultActions =
407                                    portletResourceActionsBag.getResourceGuestDefaultActions();
408    
409                            checkPortletGuestDefaultActions(guestDefaultActions);
410    
411                            Set<String> layoutManagerActions =
412                                    portletResourceActionsBag.getResourceLayoutManagerActions();
413    
414                            checkPortletLayoutManagerActions(layoutManagerActions);
415                    }
416    
417                    return new ArrayList<>(actions);
418            }
419    
420            @Override
421            public List<String> getPortletResourceGroupDefaultActions(String name) {
422    
423                    // This method should always be called only after
424                    // _getPortletResourceActions has been called at least once to populate
425                    // the default group actions. Check to make sure this is the case.
426                    // However, if it is not, that means the methods
427                    // getPortletResourceGuestDefaultActions and
428                    // getPortletResourceGuestDefaultActions may not work either.
429    
430                    name = PortletConstants.getRootPortletId(name);
431    
432                    PortletResourceActionsBag portletResourceActionsBag =
433                            getPortletResourceActionsBag(name);
434    
435                    return new ArrayList<>(
436                            portletResourceActionsBag.getResourceGroupDefaultActions());
437            }
438    
439            @Override
440            public List<String> getPortletResourceGuestDefaultActions(String name) {
441                    name = PortletConstants.getRootPortletId(name);
442    
443                    PortletResourceActionsBag portletResourceActionsBag =
444                            getPortletResourceActionsBag(name);
445    
446                    return new ArrayList<>(
447                            portletResourceActionsBag.getResourceGuestDefaultActions());
448            }
449    
450            @Override
451            public List<String> getPortletResourceGuestUnsupportedActions(String name) {
452                    name = PortletConstants.getRootPortletId(name);
453    
454                    PortletResourceActionsBag portletResourceActionsBag =
455                            getPortletResourceActionsBag(name);
456    
457                    Set<String> actions =
458                            portletResourceActionsBag.getResourceGuestUnsupportedActions();
459    
460                    if (actions.contains(ActionKeys.CONFIGURATION) &&
461                            actions.contains(ActionKeys.PERMISSIONS)) {
462    
463                            return new ArrayList<>(actions);
464                    }
465    
466                    actions.add(ActionKeys.CONFIGURATION);
467                    actions.add(ActionKeys.PERMISSIONS);
468    
469                    return new ArrayList<>(actions);
470            }
471    
472            @Override
473            public List<String> getPortletResourceLayoutManagerActions(String name) {
474                    name = PortletConstants.getRootPortletId(name);
475    
476                    PortletResourceActionsBag portletResourceActionsBag =
477                            getPortletResourceActionsBag(name);
478    
479                    Set<String> actions =
480                            portletResourceActionsBag.getResourceLayoutManagerActions();
481    
482                    // This check can never return an empty list. If the list is empty, it
483                    // means that the portlet does not have an explicit resource-actions
484                    // configuration file and should therefore be handled as if it has
485                    // defaults of CONFIGURATION, PREFERENCES, and VIEW.
486    
487                    if (actions.isEmpty()) {
488                            actions = new LinkedHashSet<>();
489    
490                            actions.add(ActionKeys.CONFIGURATION);
491                            actions.add(ActionKeys.PREFERENCES);
492                            actions.add(ActionKeys.VIEW);
493                    }
494    
495                    return new ArrayList<>(actions);
496            }
497    
498            @Override
499            public String getPortletRootModelResource(String portletName) {
500                    portletName = PortletConstants.getRootPortletId(portletName);
501    
502                    PortletResourceActionsBag portletResourceActionsBag =
503                            getPortletResourceActionsBag(portletName);
504    
505                    Map<String, String> portletRootModelResource =
506                            portletResourceActionsBag.getPortletRootModelResources();
507    
508                    return portletRootModelResource.get(portletName);
509            }
510    
511            @Override
512            public List<String> getResourceActions(String name) {
513                    if (name.indexOf(CharPool.PERIOD) != -1) {
514                            return getModelResourceActions(name);
515                    }
516                    else {
517                            return getPortletResourceActions(name);
518                    }
519            }
520    
521            @Override
522            public List<String> getResourceActions(
523                    String portletResource, String modelResource) {
524    
525                    List<String> actions = null;
526    
527                    if (Validator.isNull(modelResource)) {
528                            actions = getPortletResourceActions(portletResource);
529                    }
530                    else {
531                            actions = getModelResourceActions(modelResource);
532                    }
533    
534                    return actions;
535            }
536    
537            @Override
538            public List<String> getResourceGroupDefaultActions(String name) {
539                    if (name.contains(StringPool.PERIOD)) {
540                            return getModelResourceGroupDefaultActions(name);
541                    }
542                    else {
543                            return getPortletResourceGroupDefaultActions(name);
544                    }
545            }
546    
547            @Override
548            public List<String> getResourceGuestUnsupportedActions(
549                    String portletResource, String modelResource) {
550    
551                    List<String> actions = null;
552    
553                    if (Validator.isNull(modelResource)) {
554                            actions = getPortletResourceGuestUnsupportedActions(
555                                    portletResource);
556                    }
557                    else {
558                            actions = getModelResourceGuestUnsupportedActions(modelResource);
559                    }
560    
561                    return actions;
562            }
563    
564            /**
565             * @deprecated As of 6.1.0, replaced by {@link #getRoles(long, Group,
566             *             String, int[])}
567             */
568            @Deprecated
569            @Override
570            public List<Role> getRoles(
571                    long companyId, Group group, String modelResource) {
572    
573                    return getRoles(companyId, group, modelResource, null);
574            }
575    
576            @Override
577            public List<Role> getRoles(
578                    long companyId, Group group, String modelResource, int[] roleTypes) {
579    
580                    if (roleTypes == null) {
581                            roleTypes = getRoleTypes(companyId, group, modelResource);
582                    }
583    
584                    return roleLocalService.getRoles(companyId, roleTypes);
585            }
586    
587            @Override
588            public boolean hasModelResourceActions(String name) {
589                    ModelResourceActionsBag modelResourceActionsBag =
590                            getModelResourceActionsBag(name);
591    
592                    Set<String> actions = modelResourceActionsBag.getResourceActions();
593    
594                    if ((actions != null) && !actions.isEmpty()) {
595                            return true;
596                    }
597                    else {
598                            return false;
599                    }
600            }
601    
602            @Override
603            public boolean isOrganizationModelResource(String modelResource) {
604                    if (_organizationModelResources.contains(modelResource)) {
605                            return true;
606                    }
607                    else {
608                            return false;
609                    }
610            }
611    
612            @Override
613            public boolean isPortalModelResource(String modelResource) {
614                    if (_portalModelResources.contains(modelResource)) {
615                            return true;
616                    }
617                    else {
618                            return false;
619                    }
620            }
621    
622            @Override
623            public void read(
624                            String servletContextName, ClassLoader classLoader, String source)
625                    throws Exception {
626    
627                    InputStream inputStream = classLoader.getResourceAsStream(source);
628    
629                    if (inputStream == null) {
630                            if (_log.isInfoEnabled() && !source.endsWith("-ext.xml") &&
631                                    !source.startsWith("META-INF/")) {
632    
633                                    _log.info("Cannot load " + source);
634                            }
635    
636                            return;
637                    }
638    
639                    if (_log.isDebugEnabled()) {
640                            _log.debug("Loading " + source);
641                    }
642    
643                    Document document = UnsecureSAXReaderUtil.read(inputStream, true);
644    
645                    DocumentType documentType = document.getDocumentType();
646    
647                    String publicId = GetterUtil.getString(documentType.getPublicId());
648    
649                    if (publicId.equals(
650                                    "-//Liferay//DTD Resource Action Mapping 6.0.0//EN")) {
651    
652                            if (_log.isWarnEnabled()) {
653                                    _log.warn(
654                                            "Please update " + source + " to use the 6.1.0 format");
655                            }
656                    }
657    
658                    Element rootElement = document.getRootElement();
659    
660                    for (Element resourceElement : rootElement.elements("resource")) {
661                            String file = resourceElement.attributeValue("file").trim();
662    
663                            read(servletContextName, classLoader, file);
664    
665                            String extFile = StringUtil.replace(file, ".xml", "-ext.xml");
666    
667                            read(servletContextName, classLoader, extFile);
668                    }
669    
670                    read(servletContextName, document);
671            }
672    
673            /**
674             * @deprecated As of 7.0.0
675             */
676            @Deprecated
677            @Override
678            public void read(String servletContextName, InputStream inputStream)
679                    throws Exception {
680    
681                    Document document = UnsecureSAXReaderUtil.read(inputStream, true);
682    
683                    read(servletContextName, document);
684            }
685    
686            protected void checkGuestUnsupportedActions(
687                    Set<String> guestUnsupportedActions, Set<String> guestDefaultActions) {
688    
689                    // Guest default actions cannot reference guest unsupported actions
690    
691                    Iterator<String> itr = guestDefaultActions.iterator();
692    
693                    while (itr.hasNext()) {
694                            String actionId = itr.next();
695    
696                            if (guestUnsupportedActions.contains(actionId)) {
697                                    itr.remove();
698                            }
699                    }
700            }
701    
702            protected void checkModelActions(Set<String> actions) {
703                    if (!actions.contains(ActionKeys.PERMISSIONS)) {
704                            actions.add(ActionKeys.PERMISSIONS);
705                    }
706            }
707    
708            protected void checkPortletActions(Portlet portlet, Set<String> actions) {
709                    checkPortletLayoutManagerActions(actions);
710    
711                    if ((portlet != null) &&
712                            (portlet.getControlPanelEntryCategory() != null) &&
713                            !actions.contains(ActionKeys.ACCESS_IN_CONTROL_PANEL)) {
714    
715                            actions.add(ActionKeys.ACCESS_IN_CONTROL_PANEL);
716                    }
717            }
718    
719            protected void checkPortletActions(String name, Set<String> actions) {
720                    Portlet portlet = portletLocalService.getPortletById(name);
721    
722                    checkPortletActions(portlet, actions);
723            }
724    
725            protected void checkPortletGroupDefaultActions(Set<String> actions) {
726                    if (actions.isEmpty()) {
727                            actions.add(ActionKeys.VIEW);
728                    }
729            }
730    
731            protected void checkPortletGuestDefaultActions(Set<String> actions) {
732                    if (actions.isEmpty()) {
733                            actions.add(ActionKeys.VIEW);
734                    }
735            }
736    
737            protected void checkPortletLayoutManagerActions(Set<String> actions) {
738                    if (!actions.contains(ActionKeys.ACCESS_IN_CONTROL_PANEL) &&
739                            !actions.contains(ActionKeys.ADD_TO_PAGE)) {
740    
741                            actions.add(ActionKeys.ADD_TO_PAGE);
742                    }
743    
744                    if (!actions.contains(ActionKeys.CONFIGURATION)) {
745                            actions.add(ActionKeys.CONFIGURATION);
746                    }
747    
748                    if (!actions.contains(ActionKeys.PERMISSIONS)) {
749                            actions.add(ActionKeys.PERMISSIONS);
750                    }
751    
752                    if (!actions.contains(ActionKeys.PREFERENCES)) {
753                            actions.add(ActionKeys.PREFERENCES);
754                    }
755    
756                    if (!actions.contains(ActionKeys.VIEW)) {
757                            actions.add(ActionKeys.VIEW);
758                    }
759            }
760    
761            protected String getCompositeModelName(Element compositeModelNameElement) {
762                    StringBundler sb = new StringBundler();
763    
764                    Iterator<Element> itr = compositeModelNameElement.elementIterator(
765                            "model-name");
766    
767                    while (itr.hasNext()) {
768                            Element modelNameElement = itr.next();
769    
770                            sb.append(modelNameElement.getTextTrim());
771    
772                            if (itr.hasNext()) {
773                                    sb.append(_COMPOSITE_MODEL_NAME_SEPARATOR);
774                            }
775                    }
776    
777                    return sb.toString();
778            }
779    
780            protected ModelResourceActionsBag getModelResourceActionsBag(
781                    String modelName) {
782    
783                    ModelResourceActionsBag modelResourceActionsBag =
784                            _modelResourceActionsBags.get(modelName);
785    
786                    if (modelResourceActionsBag != null) {
787                            return modelResourceActionsBag;
788                    }
789    
790                    synchronized(_modelResourceActionsBags) {
791                            modelResourceActionsBag = _modelResourceActionsBags.get(modelName);
792    
793                            if (modelResourceActionsBag != null) {
794                                    return modelResourceActionsBag;
795                            }
796    
797                            modelResourceActionsBag = new ModelResourceActionsBagImpl();
798    
799                            _modelResourceActionsBags.put(modelName, modelResourceActionsBag);
800                    }
801    
802                    return modelResourceActionsBag;
803            }
804    
805            protected Element getPermissionsChildElement(
806                    Element parentElement, String childElementName) {
807    
808                    Element permissionsElement = parentElement.element("permissions");
809    
810                    if (permissionsElement != null) {
811                            return permissionsElement.element(childElementName);
812                    }
813                    else {
814                            return parentElement.element(childElementName);
815                    }
816            }
817    
818            protected Set<String> getPortletMimeTypeActions(String name) {
819                    Set<String> actions = new LinkedHashSet<>();
820    
821                    Portlet portlet = portletLocalService.getPortletById(name);
822    
823                    if (portlet != null) {
824                            Map<String, Set<String>> portletModes = portlet.getPortletModes();
825    
826                            Set<String> mimeTypePortletModes = portletModes.get(
827                                    ContentTypes.TEXT_HTML);
828    
829                            if (mimeTypePortletModes != null) {
830                                    for (String actionId : mimeTypePortletModes) {
831                                            if (StringUtil.equalsIgnoreCase(actionId, "edit")) {
832                                                    actions.add(ActionKeys.PREFERENCES);
833                                            }
834                                            else if (StringUtil.equalsIgnoreCase(
835                                                                    actionId, "edit_guest")) {
836    
837                                                    actions.add(ActionKeys.GUEST_PREFERENCES);
838                                            }
839                                            else {
840                                                    actions.add(StringUtil.toUpperCase(actionId));
841                                            }
842                                    }
843                            }
844                    }
845                    else {
846                            if (_log.isDebugEnabled()) {
847                                    _log.debug(
848                                            "Unable to obtain resource actions for unknown portlet " +
849                                                    name);
850                            }
851                    }
852    
853                    return actions;
854            }
855    
856            protected PortletResourceActionsBag getPortletResourceActionsBag(
857                    String portletName) {
858    
859                    PortletResourceActionsBag portletResourceActionsBag =
860                            _portletResourceActionsBags.get(portletName);
861    
862                    if (portletResourceActionsBag != null) {
863                            return portletResourceActionsBag;
864                    }
865    
866                    synchronized(_portletResourceActionsBags) {
867                            portletResourceActionsBag = _portletResourceActionsBags.get(
868                                    portletName);
869    
870                            if (portletResourceActionsBag != null) {
871                                    return portletResourceActionsBag;
872                            }
873    
874                            portletResourceActionsBag = new PortletResourceActionsBagImpl();
875    
876                            _portletResourceActionsBags.put(
877                                    portletName, portletResourceActionsBag);
878                    }
879    
880                    return portletResourceActionsBag;
881            }
882    
883            protected String getResourceBundlesString(
884                    HttpServletRequest request, String key) {
885    
886                    Locale locale = RequestUtils.getUserLocale(request, null);
887    
888                    return getResourceBundlesString(locale, key);
889            }
890    
891            protected String getResourceBundlesString(Locale locale, String key) {
892                    if ((locale == null) || (key == null)) {
893                            return null;
894                    }
895    
896                    List<ResourceBundle> resourceBundles = null;
897    
898                    try {
899                            String languageId = LocaleUtil.toLanguageId(locale);
900    
901                            resourceBundles = _resourceBundles.getService(languageId);
902                    }
903                    catch (Exception e) {
904                            _log.error(e, e);
905    
906                            return null;
907                    }
908    
909                    for (ResourceBundle resourceBundle : resourceBundles) {
910                            if (resourceBundle.containsKey(key)) {
911                                    return ResourceBundleUtil.getString(resourceBundle, key);
912                            }
913                    }
914    
915                    return null;
916            }
917    
918            protected int[] getRoleTypes(
919                    long companyId, Group group, String modelResource) {
920    
921                    int[] types = RoleConstants.TYPES_REGULAR_AND_SITE;
922    
923                    if (isPortalModelResource(modelResource)) {
924                            if (modelResource.equals(Organization.class.getName()) ||
925                                    modelResource.equals(User.class.getName())) {
926    
927                                    types = RoleConstants.TYPES_ORGANIZATION_AND_REGULAR;
928                            }
929                            else {
930                                    types = RoleConstants.TYPES_REGULAR;
931                            }
932                    }
933                    else {
934                            if (group != null) {
935                                    if (group.isLayout()) {
936                                            try {
937                                                    group = GroupServiceUtil.getGroup(
938                                                            group.getParentGroupId());
939                                            }
940                                            catch (Exception e) {
941                                            }
942                                    }
943    
944                                    if (group.isOrganization()) {
945                                            types =
946                                                    RoleConstants.TYPES_ORGANIZATION_AND_REGULAR_AND_SITE;
947                                    }
948                                    else if (group.isUser()) {
949                                            types = RoleConstants.TYPES_REGULAR;
950                                    }
951                            }
952                    }
953    
954                    return types;
955            }
956    
957            protected void read(String servletContextName, Document document)
958                    throws Exception {
959    
960                    Element rootElement = document.getRootElement();
961    
962                    if (PropsValues.RESOURCE_ACTIONS_READ_PORTLET_RESOURCES) {
963                            for (Element portletResourceElement :
964                                            rootElement.elements("portlet-resource")) {
965    
966                                    readPortletResource(servletContextName, portletResourceElement);
967                            }
968                    }
969    
970                    for (Element modelResourceElement :
971                                    rootElement.elements("model-resource")) {
972    
973                            readModelResource(servletContextName, modelResourceElement);
974                    }
975            }
976    
977            protected List<String> readActionKeys(Element parentElement) {
978                    List<String> actions = new ArrayList<>();
979    
980                    for (Element actionKeyElement : parentElement.elements("action-key")) {
981                            String actionKey = actionKeyElement.getTextTrim();
982    
983                            if (Validator.isNull(actionKey)) {
984                                    continue;
985                            }
986    
987                            actions.add(actionKey);
988                    }
989    
990                    return actions;
991            }
992    
993            protected void readGroupDefaultActions(
994                    Element parentElement, Set<String> groupDefaultActions) {
995    
996                    Element groupDefaultsElement = getPermissionsChildElement(
997                            parentElement, "site-member-defaults");
998    
999                    if (groupDefaultsElement == null) {
1000                            groupDefaultsElement = getPermissionsChildElement(
1001                                    parentElement, "community-defaults");
1002    
1003                            if (_log.isWarnEnabled() && (groupDefaultsElement != null)) {
1004                                    _log.warn(
1005                                            "The community-defaults element is deprecated. Use the " +
1006                                                    "site-member-defaults element instead.");
1007                            }
1008                    }
1009    
1010                    groupDefaultActions.addAll(readActionKeys(groupDefaultsElement));
1011            }
1012    
1013            protected void readGuestDefaultActions(
1014                    Element parentElement, Set<String> guestDefaultActions) {
1015    
1016                    Element guestDefaultsElement = getPermissionsChildElement(
1017                            parentElement, "guest-defaults");
1018    
1019                    guestDefaultActions.addAll(readActionKeys(guestDefaultsElement));
1020            }
1021    
1022            protected void readGuestUnsupportedActions(
1023                    Element parentElement, Set<String> guestUnsupportedActions,
1024                    Set<String> guestDefaultActions) {
1025    
1026                    Element guestUnsupportedElement = getPermissionsChildElement(
1027                            parentElement, "guest-unsupported");
1028    
1029                    guestUnsupportedActions.addAll(readActionKeys(guestUnsupportedElement));
1030    
1031                    checkGuestUnsupportedActions(
1032                            guestUnsupportedActions, guestDefaultActions);
1033            }
1034    
1035            protected void readLayoutManagerActions(
1036                    Element parentElement, Set<String> layoutManagerActions,
1037                    Set<String> supportsActions) {
1038    
1039                    Element layoutManagerElement = getPermissionsChildElement(
1040                            parentElement, "layout-manager");
1041    
1042                    if (layoutManagerElement != null) {
1043                            layoutManagerActions.addAll(readActionKeys(layoutManagerElement));
1044                    }
1045                    else {
1046                            layoutManagerActions.addAll(supportsActions);
1047                    }
1048            }
1049    
1050            protected void readModelResource(
1051                            String servletContextName, Element modelResourceElement)
1052                    throws Exception {
1053    
1054                    String name = modelResourceElement.elementTextTrim("model-name");
1055    
1056                    if (Validator.isNull(name)) {
1057                            name = getCompositeModelName(
1058                                    modelResourceElement.element("composite-model-name"));
1059                    }
1060    
1061                    if (GetterUtil.getBoolean(
1062                                    modelResourceElement.attributeValue("organization"))) {
1063    
1064                            _organizationModelResources.add(name);
1065                    }
1066    
1067                    if (GetterUtil.getBoolean(
1068                                    modelResourceElement.attributeValue("portal"))) {
1069    
1070                            _portalModelResources.add(name);
1071                    }
1072    
1073                    ModelResourceActionsBag modelResourceActionsBag =
1074                            getModelResourceActionsBag(name);
1075    
1076                    Element portletRefElement = modelResourceElement.element("portlet-ref");
1077    
1078                    for (Element portletNameElement :
1079                                    portletRefElement.elements("portlet-name")) {
1080    
1081                            String portletName = portletNameElement.getTextTrim();
1082    
1083                            if (servletContextName != null) {
1084                                    portletName = portletName.concat(
1085                                            PortletConstants.WAR_SEPARATOR).concat(servletContextName);
1086                            }
1087    
1088                            portletName = JS.getSafeName(portletName);
1089    
1090                            // Reference for a portlet to child models
1091    
1092                            PortletResourceActionsBag portletResourceActionsBag =
1093                                    getPortletResourceActionsBag(portletName);
1094    
1095                            Set<String> modelResources =
1096                                    portletResourceActionsBag.getResources();
1097    
1098                            modelResources.add(name);
1099    
1100                            // Reference for a model to parent portlets
1101    
1102                            Set<String> portletResources =
1103                                    modelResourceActionsBag.getResources();
1104    
1105                            portletResources.add(portletName);
1106    
1107                            // Reference for a model to root portlets
1108    
1109                            boolean root = GetterUtil.getBoolean(
1110                                    modelResourceElement.elementText("root"));
1111    
1112                            if (root) {
1113                                    Map<String, String> portletRootModelResource =
1114                                            portletResourceActionsBag.getPortletRootModelResources();
1115    
1116                                    portletRootModelResource.put(portletName, name);
1117                            }
1118                    }
1119    
1120                    double weight = GetterUtil.getDouble(
1121                            modelResourceElement.elementTextTrim("weight"), 100);
1122    
1123                    Map<String, Double> modelResourceWeights =
1124                            modelResourceActionsBag.getResourceWeights();
1125    
1126                    modelResourceWeights.put(name, weight);
1127    
1128                    Set<String> modelResourceActions =
1129                            modelResourceActionsBag.getResourceActions();
1130    
1131                    readSupportsActions(modelResourceElement, modelResourceActions);
1132    
1133                    checkModelActions(modelResourceActions);
1134    
1135                    if (modelResourceActions.size() > 64) {
1136                            throw new ResourceActionsException(
1137                                    "There are more than 64 actions for resource " + name);
1138                    }
1139    
1140                    Set<String> modelResourceGroupDefaultActions =
1141                            modelResourceActionsBag.getResourceGroupDefaultActions();
1142    
1143                    readGroupDefaultActions(
1144                            modelResourceElement, modelResourceGroupDefaultActions);
1145    
1146                    Set<String> modelResourceGuestDefaultActions =
1147                            modelResourceActionsBag.getResourceGuestDefaultActions();
1148    
1149                    readGuestDefaultActions(
1150                            modelResourceElement, modelResourceGuestDefaultActions);
1151    
1152                    Set<String> modelResourceGuestUnsupportedActions =
1153                            modelResourceActionsBag.getResourceGuestUnsupportedActions();
1154    
1155                    readGuestUnsupportedActions(
1156                            modelResourceElement, modelResourceGuestUnsupportedActions,
1157                            modelResourceGuestDefaultActions);
1158    
1159                    Set<String> modelResourceOwnerDefaultActions =
1160                            modelResourceActionsBag.getResourceOwnerDefaultActions();
1161    
1162                    readOwnerDefaultActions(
1163                            modelResourceElement, modelResourceOwnerDefaultActions);
1164            }
1165    
1166            protected void readOwnerDefaultActions(
1167                    Element parentElement, Set<String> ownerDefaultActions) {
1168    
1169                    Element ownerDefaultsElement = getPermissionsChildElement(
1170                            parentElement, "owner-defaults");
1171    
1172                    if (ownerDefaultsElement == null) {
1173                            return;
1174                    }
1175    
1176                    ownerDefaultActions.addAll(readActionKeys(ownerDefaultsElement));
1177            }
1178    
1179            protected void readPortletResource(
1180                            String servletContextName, Element portletResourceElement)
1181                    throws Exception {
1182    
1183                    String name = portletResourceElement.elementTextTrim("portlet-name");
1184    
1185                    if (servletContextName != null) {
1186                            name = name.concat(PortletConstants.WAR_SEPARATOR).concat(
1187                                    servletContextName);
1188                    }
1189    
1190                    name = JS.getSafeName(name);
1191    
1192                    PortletResourceActionsBag portletResourceActionsBag =
1193                            getPortletResourceActionsBag(name);
1194    
1195                    Set<String> portletResourceActions =
1196                            portletResourceActionsBag.getResourceActions();
1197    
1198                    readSupportsActions(portletResourceElement, portletResourceActions);
1199    
1200                    portletResourceActions.addAll(getPortletMimeTypeActions(name));
1201    
1202                    if (!name.equals(PortletKeys.PORTAL)) {
1203                            checkPortletActions(name, portletResourceActions);
1204                    }
1205    
1206                    if (portletResourceActions.size() > 64) {
1207                            throw new ResourceActionsException(
1208                                    "There are more than 64 actions for resource " + name);
1209                    }
1210    
1211                    Set<String> portletResourceGroupDefaultActions =
1212                            portletResourceActionsBag.getResourceGroupDefaultActions();
1213    
1214                    readGroupDefaultActions(
1215                            portletResourceElement, portletResourceGroupDefaultActions);
1216    
1217                    Set<String> portletResourceGuestDefaultActions =
1218                            portletResourceActionsBag.getResourceGuestDefaultActions();
1219    
1220                    readGuestDefaultActions(
1221                            portletResourceElement, portletResourceGuestDefaultActions);
1222    
1223                    Set<String> portletResourceGuestUnsupportedActions =
1224                            portletResourceActionsBag.getResourceGuestUnsupportedActions();
1225    
1226                    readGuestUnsupportedActions(
1227                            portletResourceElement, portletResourceGuestUnsupportedActions,
1228                            portletResourceGuestDefaultActions);
1229    
1230                    Set<String> portletResourceLayoutManagerActions =
1231                            portletResourceActionsBag.getResourceLayoutManagerActions();
1232    
1233                    readLayoutManagerActions(
1234                            portletResourceElement, portletResourceLayoutManagerActions,
1235                            portletResourceActions);
1236            }
1237    
1238            protected Set<String> readSupportsActions(
1239                    Element parentElement, Set<String> supportsActions) {
1240    
1241                    Element supportsElement = getPermissionsChildElement(
1242                            parentElement, "supports");
1243    
1244                    supportsActions.addAll(readActionKeys(supportsElement));
1245    
1246                    return supportsActions;
1247            }
1248    
1249            @BeanReference(type = PortletLocalService.class)
1250            protected PortletLocalService portletLocalService;
1251    
1252            @BeanReference(type = ResourceActionLocalService.class)
1253            protected ResourceActionLocalService resourceActionLocalService;
1254    
1255            @BeanReference(type = RoleLocalService.class)
1256            protected RoleLocalService roleLocalService;
1257    
1258            private static final String _ACTION_NAME_PREFIX = "action.";
1259    
1260            private static final String _COMPOSITE_MODEL_NAME_SEPARATOR =
1261                    StringPool.DASH;
1262    
1263            private static final String _MODEL_RESOURCE_NAME_PREFIX = "model.resource.";
1264    
1265            private static final Log _log = LogFactoryUtil.getLog(
1266                    ResourceActionsImpl.class);
1267    
1268            private Map<String, ModelResourceActionsBag> _modelResourceActionsBags;
1269            private final Set<String> _organizationModelResources = new HashSet<>();
1270            private final Set<String> _portalModelResources = new HashSet<>();
1271            private Map<String, PortletResourceActionsBag> _portletResourceActionsBags;
1272            private final ServiceTrackerMap<String, List<ResourceBundle>>
1273                    _resourceBundles;
1274    
1275    }