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, 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.workplace.comparison;
029
030import org.opencms.db.CmsDbEntryNotFoundException;
031import org.opencms.file.CmsObject;
032import org.opencms.file.CmsProject;
033import org.opencms.file.CmsProperty;
034import org.opencms.file.CmsResource;
035import org.opencms.file.history.I_CmsHistoryResource;
036import org.opencms.loader.CmsLoaderException;
037import org.opencms.main.CmsException;
038import org.opencms.main.CmsLog;
039import org.opencms.main.OpenCms;
040import org.opencms.security.CmsPrincipal;
041import org.opencms.util.CmsDateUtil;
042import org.opencms.workplace.commons.Messages;
043
044import java.text.DateFormat;
045import java.util.ArrayList;
046import java.util.Date;
047import java.util.Iterator;
048import java.util.List;
049
050import org.apache.commons.logging.Log;
051
052/**
053 * Comparison of two OpenCms resources.<p>
054 */
055public class CmsResourceComparison {
056
057    /** Constant indicating that an item (e.g. element or property) has been added.<p> */
058    public static final String TYPE_ADDED = "added";
059
060    /** Constant indicating that an item has been changed.<p> */
061    public static final String TYPE_CHANGED = "changed";
062
063    /** Constant indicating that an item has been removed.<p> */
064    public static final String TYPE_REMOVED = "removed";
065
066    /** Constant indicating that an item has not been changed.<p> */
067    public static final String TYPE_UNCHANGED = "unchanged";
068
069    /** The log object for this class. */
070    private static final Log LOG = CmsLog.getLog(CmsResourceComparison.class);
071
072    /**
073     * Constructs a new resource comparison object.<p>
074     *
075     */
076    protected CmsResourceComparison() {
077
078        super();
079    }
080
081    /**
082     * Helper method that collects all meta attributes of the two file versions and
083     * finds out, which of the attributes were added, removed, modified or remain unchanged.<p>
084     *
085     * @param cms the CmsObject to use
086     * @param resource1 the first resource to read the properties from
087     * @param resource2 the second resource to read the properties from
088     *
089     * @return a list of the compared attributes
090     */
091    public static List<CmsAttributeComparison> compareAttributes(
092        CmsObject cms,
093        CmsResource resource1,
094        CmsResource resource2) {
095
096        List<CmsAttributeComparison> comparedAttributes = new ArrayList<CmsAttributeComparison>();
097        comparedAttributes.add(
098            new CmsAttributeComparison(
099                Messages.GUI_HISTORY_COLS_SIZE_0,
100                String.valueOf(resource1.getLength()),
101                String.valueOf(resource2.getLength())));
102        String release1;
103        if (CmsResource.DATE_RELEASED_DEFAULT == resource1.getDateReleased()) {
104            release1 = "-";
105        } else {
106            release1 = CmsDateUtil.getDateTime(
107                new Date(resource1.getDateReleased()),
108                DateFormat.SHORT,
109                cms.getRequestContext().getLocale());
110        }
111        String release2;
112        if (CmsResource.DATE_RELEASED_DEFAULT == resource2.getDateReleased()) {
113            release2 = "-";
114        } else {
115            release2 = CmsDateUtil.getDateTime(
116                new Date(resource2.getDateReleased()),
117                DateFormat.SHORT,
118                cms.getRequestContext().getLocale());
119        }
120        comparedAttributes.add(new CmsAttributeComparison(Messages.GUI_LABEL_DATE_RELEASED_0, release1, release2));
121        String expire1;
122        if (CmsResource.DATE_EXPIRED_DEFAULT == resource1.getDateExpired()) {
123            expire1 = "-";
124        } else {
125            expire1 = CmsDateUtil.getDateTime(
126                new Date(resource1.getDateExpired()),
127                DateFormat.SHORT,
128                cms.getRequestContext().getLocale());
129        }
130        String expire2;
131        if (CmsResource.DATE_EXPIRED_DEFAULT == resource2.getDateExpired()) {
132            expire2 = "-";
133        } else {
134            expire2 = CmsDateUtil.getDateTime(
135                new Date(resource2.getDateExpired()),
136                DateFormat.SHORT,
137                cms.getRequestContext().getLocale());
138        }
139        comparedAttributes.add(new CmsAttributeComparison(Messages.GUI_LABEL_DATE_EXPIRED_0, expire1, expire2));
140        comparedAttributes.add(
141            new CmsAttributeComparison(
142                Messages.GUI_PERMISSION_INTERNAL_0,
143                String.valueOf(resource1.isInternal()),
144                String.valueOf(resource2.isInternal())));
145        String dateLastModified1 = CmsDateUtil.getDateTime(
146            new Date(resource1.getDateLastModified()),
147            DateFormat.SHORT,
148            cms.getRequestContext().getLocale());
149        String dateLastModified2 = CmsDateUtil.getDateTime(
150            new Date(resource2.getDateLastModified()),
151            DateFormat.SHORT,
152            cms.getRequestContext().getLocale());
153        comparedAttributes.add(
154            new CmsAttributeComparison(Messages.GUI_LABEL_DATE_LAST_MODIFIED_0, dateLastModified1, dateLastModified2));
155        try {
156            String type1 = OpenCms.getResourceManager().getResourceType(resource1.getTypeId()).getTypeName();
157            String type2 = OpenCms.getResourceManager().getResourceType(resource2.getTypeId()).getTypeName();
158            comparedAttributes.add(new CmsAttributeComparison(Messages.GUI_HISTORY_COLS_FILE_TYPE_0, type1, type2));
159        } catch (CmsLoaderException e) {
160            LOG.debug(e.getMessage(), e);
161        }
162        String dateCreated1 = CmsDateUtil.getDateTime(
163            new Date(resource1.getDateCreated()),
164            DateFormat.SHORT,
165            cms.getRequestContext().getLocale());
166        String dateCreated2 = CmsDateUtil.getDateTime(
167            new Date(resource2.getDateCreated()),
168            DateFormat.SHORT,
169            cms.getRequestContext().getLocale());
170        comparedAttributes.add(
171            new CmsAttributeComparison(Messages.GUI_HISTORY_COLS_DATE_PUBLISHED_0, dateCreated1, dateCreated2));
172        try {
173            String userLastModified1 = resource1.getUserLastModified().toString();
174            try {
175                userLastModified1 = CmsPrincipal.readPrincipalIncludingHistory(
176                    cms,
177                    resource1.getUserLastModified()).getName();
178            } catch (CmsDbEntryNotFoundException e) {
179                // ignore
180            }
181            String userLastModified2 = resource2.getUserLastModified().toString();
182            try {
183                userLastModified2 = CmsPrincipal.readPrincipalIncludingHistory(
184                    cms,
185                    resource2.getUserLastModified()).getName();
186            } catch (CmsDbEntryNotFoundException e) {
187                // ignore
188            }
189            comparedAttributes.add(
190                new CmsAttributeComparison(
191                    Messages.GUI_LABEL_USER_LAST_MODIFIED_0,
192                    userLastModified1,
193                    userLastModified2));
194        } catch (CmsException e) {
195            LOG.error(e.getMessage(), e);
196        }
197        String path1 = cms.getRequestContext().removeSiteRoot(resource1.getRootPath());
198        String path2 = cms.getRequestContext().removeSiteRoot(resource2.getRootPath());
199        comparedAttributes.add(new CmsAttributeComparison(Messages.GUI_HISTORY_COLS_RESOURCE_PATH_0, path1, path2));
200        return comparedAttributes;
201    }
202
203    /**
204     * Helper method that finds out, which of the properties were added, removed, modified or remain unchanged.<p>
205     *
206     * @param cms the CmsObject to use
207     * @param resource1 the first resource to read the properties from
208     * @param version1 the version of the first resource
209     * @param resource2 the second resource to read the properties from
210     * @param version2 the version of the second resource
211     *
212     * @return a list of the compared attributes
213     *
214     * @throws CmsException if something goes wrong
215     */
216    public static List<CmsAttributeComparison> compareProperties(
217        CmsObject cms,
218        CmsResource resource1,
219        String version1,
220        CmsResource resource2,
221        String version2) throws CmsException {
222
223        List<CmsProperty> properties1;
224        if (resource1 instanceof I_CmsHistoryResource) {
225            properties1 = cms.readHistoryPropertyObjects((I_CmsHistoryResource)resource1);
226        } else {
227            if (Integer.parseInt(version1) < 0) {
228                // switch to the online project
229                CmsProject prj = cms.getRequestContext().getCurrentProject();
230                try {
231                    cms.getRequestContext().setCurrentProject(cms.readProject(CmsProject.ONLINE_PROJECT_ID));
232                    properties1 = cms.readPropertyObjects(resource1, false);
233                } finally {
234                    cms.getRequestContext().setCurrentProject(prj);
235                }
236            } else {
237                properties1 = cms.readPropertyObjects(resource1, false);
238            }
239        }
240        List<CmsProperty> properties2;
241        if (resource2 instanceof I_CmsHistoryResource) {
242            properties2 = cms.readHistoryPropertyObjects((I_CmsHistoryResource)resource2);
243        } else {
244            if (Integer.parseInt(version2) < 0) {
245                // switch to the online project
246                CmsProject prj = cms.getRequestContext().getCurrentProject();
247                try {
248                    cms.getRequestContext().setCurrentProject(cms.readProject(CmsProject.ONLINE_PROJECT_ID));
249                    properties2 = cms.readPropertyObjects(resource2, false);
250                } finally {
251                    cms.getRequestContext().setCurrentProject(prj);
252                }
253            } else {
254                properties2 = cms.readPropertyObjects(resource2, false);
255            }
256        }
257        List<CmsAttributeComparison> comparedProperties = new ArrayList<CmsAttributeComparison>();
258        List<CmsProperty> removedProperties = new ArrayList<CmsProperty>(properties1);
259        removedProperties.removeAll(properties2);
260        List<CmsProperty> addedProperties = new ArrayList<CmsProperty>(properties2);
261        addedProperties.removeAll(properties1);
262        List<CmsProperty> retainedProperties = new ArrayList<CmsProperty>(properties2);
263        retainedProperties.retainAll(properties1);
264        CmsProperty prop;
265        Iterator<CmsProperty> i = addedProperties.iterator();
266        while (i.hasNext()) {
267            prop = i.next();
268            comparedProperties.add(
269                new CmsAttributeComparison(prop.getName(), "", prop.getValue(), CmsResourceComparison.TYPE_ADDED));
270        }
271        i = removedProperties.iterator();
272        while (i.hasNext()) {
273            prop = i.next();
274            comparedProperties.add(
275                new CmsAttributeComparison(prop.getName(), prop.getValue(), "", CmsResourceComparison.TYPE_REMOVED));
276        }
277        i = retainedProperties.iterator();
278        while (i.hasNext()) {
279            prop = i.next();
280            String value1 = properties1.get(properties1.indexOf(prop)).getValue();
281            String value2 = properties2.get(properties2.indexOf(prop)).getValue();
282            if (value1.equals(value2)) {
283                comparedProperties.add(
284                    new CmsAttributeComparison(prop.getName(), value1, value2, CmsResourceComparison.TYPE_UNCHANGED));
285            } else {
286                comparedProperties.add(
287                    new CmsAttributeComparison(prop.getName(), value1, value2, CmsResourceComparison.TYPE_CHANGED));
288            }
289        }
290        return comparedProperties;
291    }
292}