001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH & Co. KG, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.ade.publish;
029
030import org.opencms.ade.publish.shared.CmsPublishOptions;
031import org.opencms.ade.publish.shared.CmsPublishResource;
032import org.opencms.ade.publish.shared.CmsPublishResourceInfo;
033import org.opencms.db.CmsPublishList;
034import org.opencms.db.CmsResourceState;
035import org.opencms.file.CmsObject;
036import org.opencms.file.CmsResource;
037import org.opencms.file.CmsResourceFilter;
038import org.opencms.file.types.CmsResourceTypePlain;
039import org.opencms.gwt.CmsIconUtil;
040import org.opencms.gwt.CmsVfsService;
041import org.opencms.gwt.shared.CmsPermissionInfo;
042import org.opencms.main.CmsException;
043import org.opencms.main.CmsLog;
044import org.opencms.main.OpenCms;
045import org.opencms.publish.CmsPublishManager;
046import org.opencms.relations.CmsRelation;
047import org.opencms.relations.CmsRelationPublishValidator;
048import org.opencms.relations.CmsRelationValidatorInfoEntry;
049import org.opencms.report.CmsWorkplaceReport;
050import org.opencms.report.I_CmsReport;
051import org.opencms.security.CmsOrganizationalUnit;
052import org.opencms.ui.components.CmsResourceIcon;
053import org.opencms.util.CmsStringUtil;
054import org.opencms.util.CmsUUID;
055import org.opencms.workplace.explorer.CmsResourceUtil;
056
057import java.util.ArrayList;
058import java.util.Collection;
059import java.util.HashMap;
060import java.util.HashSet;
061import java.util.List;
062import java.util.Locale;
063import java.util.Map;
064import java.util.Set;
065
066import org.apache.commons.logging.Log;
067
068/**
069 * ADE publishing features.<p>
070 *
071 * @since 8.0.0
072 */
073public class CmsPublish {
074
075    /**
076     * Just for passing around resources and their related together but not mixed up.<p>
077     */
078    public class ResourcesAndRelated {
079
080        /** The related resources. */
081        private Set<CmsResource> m_relatedResources = new HashSet<CmsResource>();
082
083        /** The resources. */
084        private Set<CmsResource> m_resources = new HashSet<CmsResource>();
085
086        /**
087         * Constructor.<p>
088         */
089        public ResourcesAndRelated() {
090
091            // empty
092        }
093
094        /**
095         * Checks if the given resource is present in at least one of the sets.<p>
096         *
097         * @param resource the resource to test
098         *
099         * @return <code>true</code> if the given resource is present in at least one of the sets
100         */
101        public boolean contains(CmsResource resource) {
102
103            return m_resources.contains(resource) || m_relatedResources.contains(resource);
104        }
105
106        /**
107         * Returns the related resources.<p>
108         *
109         * @return the related resources
110         */
111        public Set<CmsResource> getRelatedResources() {
112
113            return m_relatedResources;
114        }
115
116        /**
117         * Returns the resources.<p>
118         *
119         * @return the resources
120         */
121        public Set<CmsResource> getResources() {
122
123            return m_resources;
124        }
125    }
126
127    /** The number of day groups. */
128    protected static final int GROUP_DAYS_NUMBER = 3;
129
130    /** The gap between session groups. */
131    protected static final int GROUP_SESSIONS_GAP = 8 * 60 * 60 * 1000;
132
133    /** The number of session groups. */
134    protected static final int GROUP_SESSIONS_NUMBER = 2;
135
136    /** The log object for this class. */
137    private static final Log LOG = CmsLog.getLog(CmsPublish.class);
138
139    /** The current cms context. */
140    protected final CmsObject m_cms;
141
142    /** The options. */
143    protected final CmsPublishOptions m_options;
144
145    /** The current user workplace locale. */
146    protected final Locale m_workplaceLocale;
147
148    /** The relation validator instance. */
149    private CmsRelationPublishValidator m_relationValidator;
150
151    /**
152     * Creates a new instance.<p>
153     *
154     * @param cms the CMS context to use
155     */
156    public CmsPublish(CmsObject cms) {
157
158        this(cms, new HashMap<String, String>());
159    }
160
161    /**
162     * Constructor with options.<p>
163     *
164     * @param cms the current cms context
165     * @param options the options to use
166     */
167    public CmsPublish(CmsObject cms, CmsPublishOptions options) {
168
169        m_cms = cms;
170        m_workplaceLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms);
171        m_options = options;
172    }
173
174    /**
175     * Constructor with default options.<p>
176     *
177     * @param cms the current cms context
178     * @param params the additional publish parameters
179     */
180    public CmsPublish(CmsObject cms, Map<String, String> params) {
181
182        this(cms, new CmsPublishOptions(params));
183    }
184
185    /**
186     * Returns the simple name if the ou is the same as the current user's ou.<p>
187     *
188     * @param cms the CMS context
189     * @param name the fully qualified name to check
190     *
191     * @return the simple name if the ou is the same as the current user's ou
192     */
193    protected static String getOuAwareName(CmsObject cms, String name) {
194
195        String ou = CmsOrganizationalUnit.getParentFqn(name);
196        if (ou.equals(cms.getRequestContext().getCurrentUser().getOuFqn())) {
197            return CmsOrganizationalUnit.getSimpleName(name);
198        }
199        return CmsOrganizationalUnit.SEPARATOR + name;
200    }
201
202    /**
203     * Checks for possible broken links when the given list of resources would be published.<p>
204     *
205     * @param pubResources list of resources to be published
206     *
207     * @return a list of resources that would produce broken links when published
208     */
209    public List<CmsPublishResource> getBrokenResources(List<CmsResource> pubResources) {
210
211        List<CmsPublishResource> resources = new ArrayList<CmsPublishResource>();
212        CmsPublishManager publishManager = OpenCms.getPublishManager();
213
214        CmsPublishList publishList;
215        try {
216            publishList = OpenCms.getPublishManager().getPublishListAll(
217                m_cms,
218                pubResources,
219                m_options.isIncludeSiblings(),
220                true);
221            if (m_options.isIncludeRelated()) {
222                CmsPublishList related = publishManager.getRelatedResourcesToPublish(m_cms, publishList);
223                publishList = publishManager.mergePublishLists(m_cms, publishList, related);
224            }
225
226        } catch (CmsException e) {
227            // should never happen
228            LOG.error(e.getLocalizedMessage(), e);
229            return resources;
230        }
231
232        CmsRelationPublishValidator validator = new CmsRelationPublishValidator(m_cms, publishList);
233        m_relationValidator = validator;
234        for (String resourceName : validator.keySet()) {
235            CmsRelationValidatorInfoEntry infoEntry = validator.getInfoEntry(resourceName);
236            try {
237                CmsResource resource = m_cms.readResource(
238                    m_cms.getRequestContext().removeSiteRoot(resourceName),
239                    CmsResourceFilter.ALL);
240                if (resource.getState().isDeleted()) {
241                    for (CmsRelation relation : infoEntry.getRelations()) {
242                        try {
243                            CmsResource theResource = relation.getSource(m_cms, CmsResourceFilter.ALL);
244                            CmsPublishResourceInfo info = new CmsPublishResourceInfo(
245                                Messages.get().getBundle(m_workplaceLocale).key(Messages.GUI_BROKEN_LINK_ONLINE_0),
246                                CmsPublishResourceInfo.Type.BROKENLINK);
247                            // HACK: GWT serialization does not like unmodifiable collections :(
248                            // Collections.singletonList(resourceToBean(resource, info, false, null)));
249                            ArrayList<CmsPublishResource> relatedList = new ArrayList<CmsPublishResource>();
250                            relatedList.add(resourceToBean(resource, info, false, null));
251                            CmsPublishResource pubRes = resourceToBean(theResource, null, false, relatedList);
252                            resources.add(pubRes);
253                        } catch (CmsException e) {
254                            // should never happen
255                            LOG.error(e.getLocalizedMessage(), e);
256                        }
257                    }
258                } else {
259                    try {
260                        List<CmsPublishResource> related = new ArrayList<CmsPublishResource>();
261                        for (CmsRelation relation : infoEntry.getRelations()) {
262                            try {
263                                CmsResource theResource = relation.getTarget(m_cms, CmsResourceFilter.ALL);
264                                CmsPublishResource pubRes = resourceToBean(theResource, null, false, null);
265                                related.add(pubRes);
266                            } catch (CmsException e) {
267                                CmsPublishResource pubRes = relationToBean(relation);
268                                related.add(pubRes);
269                                LOG.warn(e.getLocalizedMessage(), e);
270                            }
271                        }
272                        CmsPublishResourceInfo info = new CmsPublishResourceInfo(
273                            Messages.get().getBundle(m_workplaceLocale).key(Messages.GUI_RESOURCE_MISSING_ONLINE_0),
274                            CmsPublishResourceInfo.Type.MISSING);
275                        CmsPublishResource pubRes = resourceToBean(resource, info, false, related);
276                        resources.add(pubRes);
277                    } catch (Exception e) {
278                        // should never happen
279                        LOG.error(e.getLocalizedMessage(), e);
280                    }
281                }
282            } catch (CmsException e) {
283                // should never happen
284                LOG.error(e.getLocalizedMessage(), e);
285            }
286        }
287
288        return resources;
289    }
290
291    /**
292     * Gets the relation validator instance.<p>
293     *
294     * @return the relation validator
295     */
296    public CmsRelationPublishValidator getRelationValidator() {
297
298        return m_relationValidator;
299    }
300
301    /**
302     * Publishes the given list of resources.<p>
303     *
304     * @param resources list of resources to publish
305     *
306     * @throws CmsException if something goes wrong
307     */
308    public void publishResources(List<CmsResource> resources) throws CmsException {
309
310        CmsObject cms = m_cms;
311        I_CmsReport report = new CmsWorkplaceReport(
312            cms.getRequestContext().getLocale(),
313            cms.getRequestContext().getSiteRoot(),
314            null);
315        CmsPublishManager publishManager = OpenCms.getPublishManager();
316        CmsPublishList publishList = publishManager.getPublishListAll(m_cms, resources, false, true);
317        OpenCms.getPublishManager().publishProject(m_cms, report, publishList);
318    }
319
320    /**
321     * Creates a publish resource bean from the target information of a relation object.<p>
322     *
323     * @param relation the relation to use
324     *
325     * @return the publish resource bean for the relation target
326     */
327    public CmsPublishResource relationToBean(CmsRelation relation) {
328
329        CmsPermissionInfo permissionInfo = new CmsPermissionInfo(true, false, "");
330        CmsPublishResource bean = new CmsPublishResource(
331            relation.getTargetId(),
332            relation.getTargetPath(),
333            relation.getTargetPath(),
334            CmsResourceTypePlain.getStaticTypeName(),
335            CmsResourceState.STATE_UNCHANGED,
336            permissionInfo,
337            0,
338            null,
339            null,
340            false,
341            null,
342            null);
343        bean.setBigIconClasses(CmsIconUtil.getIconClasses(CmsResourceTypePlain.getStaticTypeName(), null, false));
344        return bean;
345    }
346
347    /**
348     * Removes the given resources from the user's publish list.<p>
349     *
350     * @param idsToRemove list of structure ids identifying the resources to be removed
351     *
352     * @throws CmsException if something goes wrong
353     */
354    public void removeResourcesFromPublishList(Collection<CmsUUID> idsToRemove) throws CmsException {
355
356        OpenCms.getPublishManager().removeResourceFromUsersPubList(m_cms, idsToRemove);
357    }
358
359    /**
360     * Creates a publish resource bean instance from the given parameters.<p>
361     *
362     * @param resource the resource
363     * @param info the publish information, if any
364     * @param removable if removable
365     * @param related the list of related resources
366     *
367     * @return the publish resource bean
368     *
369     * @throws CmsException if something goes wrong
370     */
371    protected CmsPublishResource resourceToBean(
372        CmsResource resource,
373        CmsPublishResourceInfo info,
374        boolean removable,
375        List<CmsPublishResource> related)
376    throws CmsException {
377
378        CmsResourceUtil resUtil = new CmsResourceUtil(m_cms, resource);
379        CmsPermissionInfo permissionInfo = OpenCms.getADEManager().getPermissionInfo(m_cms, resource, null);
380
381        String typeName = CmsIconUtil.getDisplayType(m_cms, resource);
382        String detailTypeName = null;
383        detailTypeName = CmsResourceIcon.getDefaultFileOrDetailType(m_cms, resource);
384
385        CmsPublishResource pubResource = new CmsPublishResource(
386            resource.getStructureId(),
387            resUtil.getFullPath(),
388            resUtil.getTitle(),
389            typeName,
390            resource.getState(),
391            permissionInfo,
392            resource.getDateLastModified(),
393            resUtil.getUserLastModified(),
394            CmsVfsService.formatDateTime(m_cms, resource.getDateLastModified()),
395            removable,
396            info,
397            related);
398        pubResource.setBigIconClasses(CmsIconUtil.getIconClasses(typeName, null, false));
399        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(detailTypeName)) {
400            pubResource.setSmallIconClasses(CmsIconUtil.getIconClasses(detailTypeName, null, true));
401        }
402        return pubResource;
403    }
404
405}