001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (C) Alkacon Software (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.gwt; 029 030import org.opencms.ade.containerpage.CmsRelationTargetListBean; 031import org.opencms.file.CmsFile; 032import org.opencms.file.CmsObject; 033import org.opencms.file.CmsProperty; 034import org.opencms.file.CmsPropertyDefinition; 035import org.opencms.file.CmsResource; 036import org.opencms.file.CmsResourceFilter; 037import org.opencms.file.CmsUser; 038import org.opencms.file.CmsVfsResourceNotFoundException; 039import org.opencms.file.types.CmsResourceTypeJsp; 040import org.opencms.file.types.CmsResourceTypeXmlContainerPage; 041import org.opencms.file.types.CmsResourceTypeXmlContent; 042import org.opencms.file.types.I_CmsResourceType; 043import org.opencms.gwt.shared.CmsListInfoBean; 044import org.opencms.gwt.shared.CmsResourceStatusBean; 045import org.opencms.gwt.shared.CmsResourceStatusRelationBean; 046import org.opencms.gwt.shared.CmsResourceStatusTabId; 047import org.opencms.i18n.CmsLocaleManager; 048import org.opencms.i18n.CmsMessageContainer; 049import org.opencms.lock.CmsLock; 050import org.opencms.main.CmsException; 051import org.opencms.main.CmsLog; 052import org.opencms.main.OpenCms; 053import org.opencms.relations.CmsRelation; 054import org.opencms.relations.CmsRelationFilter; 055import org.opencms.relations.CmsRelationType; 056import org.opencms.relations.I_CmsLinkParseable; 057import org.opencms.search.galleries.CmsGallerySearch; 058import org.opencms.search.galleries.CmsGallerySearchResult; 059import org.opencms.util.CmsStringUtil; 060import org.opencms.util.CmsUUID; 061import org.opencms.workplace.explorer.CmsResourceUtil; 062import org.opencms.xml.content.CmsXmlContent; 063import org.opencms.xml.content.CmsXmlContentFactory; 064 065import java.util.ArrayList; 066import java.util.HashMap; 067import java.util.LinkedHashMap; 068import java.util.List; 069import java.util.Locale; 070import java.util.Map; 071 072import org.apache.commons.logging.Log; 073 074/** 075 * Helper class to generate all the data which is necessary for the resource status dialog(s).<p> 076 */ 077public class CmsDefaultResourceStatusProvider { 078 079 /** The log instance for this class. */ 080 private static final Log LOG = CmsLog.getLog(CmsDefaultResourceStatusProvider.class); 081 082 /** 083 * Gets the relation targets for a resource.<p> 084 * 085 * @param cms the current CMS context 086 * @param source the structure id of the resource for which we want the relation targets 087 * @param additionalIds the structure ids of additional resources to include with the relation targets 088 * @param cancelIfChanged if this is true, this method will stop immediately if it finds a changed resource among the relation targets 089 * 090 * @return a bean containing a list of relation targets 091 * 092 * @throws CmsException if something goes wrong 093 */ 094 public static CmsRelationTargetListBean getContainerpageRelationTargets( 095 CmsObject cms, 096 CmsUUID source, 097 List<CmsUUID> additionalIds, 098 boolean cancelIfChanged) throws CmsException { 099 100 CmsRelationTargetListBean result = new CmsRelationTargetListBean(); 101 CmsResource content = cms.readResource(source, CmsResourceFilter.IGNORE_EXPIRATION); 102 boolean isContainerPage = CmsResourceTypeXmlContainerPage.isContainerPage(content); 103 for (CmsUUID structureId : additionalIds) { 104 try { 105 CmsResource res = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION); 106 result.add(res); 107 if (res.getState().isChanged() && cancelIfChanged) { 108 return result; 109 } 110 } catch (CmsException e) { 111 LOG.error(e.getLocalizedMessage(), e); 112 } 113 } 114 List<CmsRelation> relations = cms.readRelations(CmsRelationFilter.relationsFromStructureId(source)); 115 for (CmsRelation relation : relations) { 116 if (relation.getType() == CmsRelationType.XSD) { 117 continue; 118 } 119 try { 120 CmsResource target = relation.getTarget(cms, CmsResourceFilter.IGNORE_EXPIRATION); 121 I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(target); 122 if (isContainerPage && (type instanceof CmsResourceTypeJsp)) { 123 // ignore formatters for container pages, as the normal user probably doesn't want to deal with them 124 continue; 125 } 126 result.add(target); 127 if (target.getState().isChanged() && cancelIfChanged) { 128 return result; 129 } 130 } catch (CmsException e) { 131 LOG.error(e.getLocalizedMessage(), e); 132 } 133 } 134 return result; 135 } 136 137 /** 138 * Collects all the data to display in the resource status dialog.<p> 139 * 140 * @param cms the current CMS context 141 * @param structureId the structure id of the resource for which we want the information 142 * @param contentLocale the content locale 143 * @param includeTargets true if relation targets should be included 144 * @param additionalStructureIds structure ids of additional resources to include with the relation targets 145 * 146 * @return the resource status information 147 * @throws CmsException if something goes wrong 148 */ 149 public CmsResourceStatusBean getResourceStatus( 150 CmsObject cms, 151 CmsUUID structureId, 152 String contentLocale, 153 boolean includeTargets, 154 List<CmsUUID> additionalStructureIds) throws CmsException { 155 156 Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms); 157 cms.getRequestContext().setLocale(locale); 158 CmsResource resource = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION); 159 String localizedTitle = null; 160 if (!CmsStringUtil.isEmptyOrWhitespaceOnly(contentLocale)) { 161 Locale realLocale = CmsLocaleManager.getLocale(contentLocale); 162 CmsGallerySearchResult result = CmsGallerySearch.searchById(cms, structureId, realLocale); 163 if (!CmsStringUtil.isEmptyOrWhitespaceOnly(result.getTitle())) { 164 localizedTitle = result.getTitle(); 165 } 166 } 167 CmsResourceUtil resourceUtil = new CmsResourceUtil(cms, resource); 168 List<CmsProperty> properties = cms.readPropertyObjects(resource, false); 169 CmsResourceStatusBean result = new CmsResourceStatusBean(); 170 result.setDateCreated(CmsVfsService.formatDateTime(cms, resource.getDateCreated())); 171 long dateExpired = resource.getDateExpired(); 172 if (dateExpired != CmsResource.DATE_EXPIRED_DEFAULT) { 173 result.setDateExpired(CmsVfsService.formatDateTime(cms, dateExpired)); 174 } 175 result.setDateLastModified(CmsVfsService.formatDateTime(cms, resource.getDateLastModified())); 176 long dateReleased = resource.getDateReleased(); 177 if (dateReleased != CmsResource.DATE_RELEASED_DEFAULT) { 178 result.setDateReleased(CmsVfsService.formatDateTime(cms, dateReleased)); 179 } 180 String lastProject = resourceUtil.getLockedInProjectName(); 181 if ("".equals(lastProject)) { 182 lastProject = null; 183 } 184 result.setLastProject(lastProject); 185 186 result.setListInfo(CmsVfsService.getPageInfo(cms, resource)); 187 CmsLock lock = cms.getLock(resource); 188 CmsUser lockOwner = null; 189 if (!lock.isUnlocked()) { 190 lockOwner = cms.readUser(lock.getUserId()); 191 result.setLockState(org.opencms.workplace.list.Messages.get().getBundle(locale).key( 192 org.opencms.workplace.list.Messages.GUI_EXPLORER_LIST_ACTION_LOCK_NAME_2, 193 lockOwner.getName(), 194 lastProject)); 195 } else { 196 result.setLockState(org.opencms.workplace.list.Messages.get().getBundle(locale).key( 197 org.opencms.workplace.list.Messages.GUI_EXPLORER_LIST_ACTION_UNLOCK_NAME_0)); 198 } 199 200 CmsProperty navText = CmsProperty.get(CmsPropertyDefinition.PROPERTY_NAVTEXT, properties); 201 if (navText != null) { 202 result.setNavText(navText.getValue()); 203 } 204 result.setPermissions(resourceUtil.getPermissionString()); 205 result.setSize(resource.getLength()); 206 result.setStateBean(resource.getState()); 207 CmsProperty title = CmsProperty.get(CmsPropertyDefinition.PROPERTY_TITLE, properties); 208 if (localizedTitle != null) { 209 result.setTitle(localizedTitle); 210 result.getListInfo().setTitle(localizedTitle); 211 } else if (title != null) { 212 result.setTitle(title.getValue()); 213 } 214 result.setUserCreated(resourceUtil.getUserCreated()); 215 result.setUserLastModified(resourceUtil.getUserLastModified()); 216 217 I_CmsResourceType resType = OpenCms.getResourceManager().getResourceType(resource.getTypeId()); 218 result.setResourceType(resType.getTypeName()); 219 result.setStructureId(resource.getStructureId()); 220 if (resType instanceof CmsResourceTypeXmlContent) { 221 CmsFile file = cms.readFile(resource); 222 CmsXmlContent content = CmsXmlContentFactory.unmarshal(cms, file); 223 List<Locale> locales = content.getLocales(); 224 List<String> localeStrings = new ArrayList<String>(); 225 for (Locale l : locales) { 226 localeStrings.add(l.toString()); 227 } 228 result.setLocales(localeStrings); 229 } 230 231 List<CmsRelation> relations = cms.readRelations(CmsRelationFilter.relationsToStructureId(resource.getStructureId())); 232 Map<CmsUUID, CmsResource> relationSources = new HashMap<CmsUUID, CmsResource>(); 233 234 if (CmsResourceTypeXmlContainerPage.isContainerPage(resource)) { 235 // People may link to the folder of a container page instead of the page itself 236 try { 237 CmsResource parent = cms.readParentFolder(resource.getStructureId()); 238 List<CmsRelation> parentRelations = cms.readRelations(CmsRelationFilter.relationsToStructureId(parent.getStructureId())); 239 relations.addAll(parentRelations); 240 } catch (CmsException e) { 241 LOG.error(e.getLocalizedMessage(), e); 242 } 243 } 244 245 // find all distinct relation sources 246 for (CmsRelation relation : relations) { 247 CmsResource currentSource = relation.getSource(cms, CmsResourceFilter.IGNORE_EXPIRATION); 248 relationSources.put(currentSource.getStructureId(), currentSource); 249 } 250 251 for (CmsResource relationResource : relationSources.values()) { 252 try { 253 CmsResourceStatusRelationBean relationBean = createRelationBean(cms, relationResource); 254 result.getRelationSources().add(relationBean); 255 } catch (CmsVfsResourceNotFoundException notfound) { 256 LOG.error(notfound.getLocalizedMessage(), notfound); 257 continue; 258 } 259 } 260 if (includeTargets) { 261 result.getRelationTargets().addAll(getTargets(cms, structureId, additionalStructureIds)); 262 } 263 result.setTabs(getTabClientData(cms, resource)); 264 return result; 265 } 266 267 /** 268 * Gets the list of relation targets for a resource.<p> 269 * 270 * @param cms the current CMS context 271 * @param structureId the structure id of the resource for which we want the relation targets 272 * @param additionalStructureIds structure ids of additional resources to include with the relation target 273 * 274 * @return the list of relation beans for the relation targets 275 * 276 * @throws CmsException if something goes wrong 277 */ 278 protected List<CmsResourceStatusRelationBean> getTargets( 279 CmsObject cms, 280 CmsUUID structureId, 281 List<CmsUUID> additionalStructureIds) throws CmsException { 282 283 CmsRelationTargetListBean listBean = getContainerpageRelationTargets( 284 cms, 285 structureId, 286 additionalStructureIds, 287 false); 288 List<CmsResourceStatusRelationBean> result = new ArrayList<CmsResourceStatusRelationBean>(); 289 for (CmsResource target : listBean.getResources()) { 290 try { 291 CmsResourceStatusRelationBean relationBean = createRelationBean(cms, target); 292 result.add(relationBean); 293 } catch (CmsException e) { 294 LOG.error(e.getLocalizedMessage(), e); 295 } 296 } 297 return result; 298 299 } 300 301 /** 302 * Creates a bean for a single resource which is part of a relation list.<p> 303 * 304 * @param cms the current CMS context 305 * @param relationResource the resource 306 * 307 * @return the status bean for the resource 308 * 309 * @throws CmsException if something goes wrong 310 */ 311 CmsResourceStatusRelationBean createRelationBean(CmsObject cms, CmsResource relationResource) throws CmsException { 312 313 CmsListInfoBean sourceBean = CmsVfsService.getPageInfo(cms, relationResource); 314 String link = null; 315 try { 316 link = OpenCms.getLinkManager().substituteLink(cms, relationResource); 317 } catch (Exception e) { 318 LOG.warn(e.getLocalizedMessage(), e); 319 } 320 CmsResourceStatusRelationBean relationBean = new CmsResourceStatusRelationBean( 321 sourceBean, 322 link, 323 relationResource.getStructureId()); 324 if (CmsResourceTypeXmlContent.isXmlContent(relationResource)) { 325 relationBean.setIsXmlContent(true); 326 } 327 String sitePath = cms.getSitePath(relationResource); 328 relationBean.setSitePath(sitePath); 329 return relationBean; 330 } 331 332 /** 333 * Determines the arrangement of tabs to display, together with their labels.<p> 334 * 335 * @param cms the current CMS context 336 * @param res the resource for which the dialog should be displayed 337 * @return the tab configuration for the dialog 338 */ 339 private LinkedHashMap<CmsResourceStatusTabId, String> getTabClientData(CmsObject cms, CmsResource res) { 340 341 Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms); 342 LinkedHashMap<CmsResourceStatusTabId, String> result = new LinkedHashMap<CmsResourceStatusTabId, String>(); 343 Map<CmsResourceStatusTabId, CmsMessageContainer> tabs = getTabData(res); 344 for (Map.Entry<CmsResourceStatusTabId, CmsMessageContainer> entry : tabs.entrySet()) { 345 result.put(entry.getKey(), entry.getValue().key(locale)); 346 } 347 return result; 348 } 349 350 /** 351 * Determines the arrangement of tabs to display, together with their labels.<p> 352 * 353 * @param res the resource for which the dialog should be displayed 354 * @return the tab configuration for the dialog 355 */ 356 private Map<CmsResourceStatusTabId, CmsMessageContainer> getTabData(CmsResource res) { 357 358 Map<CmsResourceStatusTabId, CmsMessageContainer> tabs; 359 if (CmsResourceTypeXmlContainerPage.isContainerPage(res)) { 360 tabs = CmsResourceStatusConstants.STATUS_TABS_CONTAINER_PAGE; 361 } else if (OpenCms.getResourceManager().getResourceType(res) instanceof I_CmsLinkParseable) { 362 tabs = CmsResourceStatusConstants.STATUS_TABS_CONTENT; 363 } else { 364 tabs = CmsResourceStatusConstants.STATUS_TABS_OTHER; 365 } 366 return tabs; 367 } 368 369}