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.CmsPermissionInfo; 045import org.opencms.gwt.shared.CmsResourceStatusBean; 046import org.opencms.gwt.shared.CmsResourceStatusRelationBean; 047import org.opencms.gwt.shared.CmsResourceStatusTabId; 048import org.opencms.i18n.CmsLocaleManager; 049import org.opencms.i18n.CmsMessageContainer; 050import org.opencms.lock.CmsLock; 051import org.opencms.main.CmsException; 052import org.opencms.main.CmsLog; 053import org.opencms.main.OpenCms; 054import org.opencms.relations.CmsRelation; 055import org.opencms.relations.CmsRelationFilter; 056import org.opencms.relations.CmsRelationType; 057import org.opencms.relations.I_CmsLinkParseable; 058import org.opencms.search.galleries.CmsGallerySearch; 059import org.opencms.search.galleries.CmsGallerySearchResult; 060import org.opencms.site.CmsSite; 061import org.opencms.util.CmsStringUtil; 062import org.opencms.util.CmsUUID; 063import org.opencms.workplace.CmsWorkplace; 064import org.opencms.workplace.explorer.CmsResourceUtil; 065import org.opencms.xml.content.CmsXmlContent; 066import org.opencms.xml.content.CmsXmlContentFactory; 067 068import java.util.ArrayList; 069import java.util.Collections; 070import java.util.Comparator; 071import java.util.HashMap; 072import java.util.LinkedHashMap; 073import java.util.List; 074import java.util.Locale; 075import java.util.Map; 076 077import org.apache.commons.logging.Log; 078 079import com.google.common.collect.ComparisonChain; 080import com.google.common.collect.Maps; 081 082/** 083 * Helper class to generate all the data which is necessary for the resource status dialog(s).<p> 084 */ 085public class CmsDefaultResourceStatusProvider { 086 087 /** The log instance for this class. */ 088 private static final Log LOG = CmsLog.getLog(CmsDefaultResourceStatusProvider.class); 089 090 /** 091 * Gets the relation targets for a resource.<p> 092 * 093 * @param cms the current CMS context 094 * @param source the structure id of the resource for which we want the relation targets 095 * @param additionalIds the structure ids of additional resources to include with the relation targets 096 * @param cancelIfChanged if this is true, this method will stop immediately if it finds a changed resource among the relation targets 097 * 098 * @return a bean containing a list of relation targets 099 * 100 * @throws CmsException if something goes wrong 101 */ 102 public static CmsRelationTargetListBean getContainerpageRelationTargets( 103 CmsObject cms, 104 CmsUUID source, 105 List<CmsUUID> additionalIds, 106 boolean cancelIfChanged) throws CmsException { 107 108 CmsRelationTargetListBean result = new CmsRelationTargetListBean(); 109 CmsResource content = cms.readResource(source, CmsResourceFilter.ALL); 110 boolean isContainerPage = CmsResourceTypeXmlContainerPage.isContainerPage(content); 111 for (CmsUUID structureId : additionalIds) { 112 try { 113 CmsResource res = cms.readResource(structureId, CmsResourceFilter.ALL); 114 result.add(res); 115 if (res.getState().isChanged() && cancelIfChanged) { 116 return result; 117 } 118 } catch (CmsException e) { 119 LOG.error(e.getLocalizedMessage(), e); 120 } 121 } 122 List<CmsRelation> relations = cms.readRelations(CmsRelationFilter.relationsFromStructureId(source)); 123 for (CmsRelation relation : relations) { 124 if (relation.getType() == CmsRelationType.XSD) { 125 continue; 126 } 127 try { 128 CmsResource target = relation.getTarget(cms, CmsResourceFilter.ALL); 129 I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(target); 130 if (isContainerPage && (type instanceof CmsResourceTypeJsp)) { 131 // ignore formatters for container pages, as the normal user probably doesn't want to deal with them 132 continue; 133 } 134 result.add(target); 135 if (target.getState().isChanged() && cancelIfChanged) { 136 return result; 137 } 138 } catch (CmsException e) { 139 LOG.debug(e.getLocalizedMessage(), e); 140 } 141 } 142 return result; 143 } 144 145 /** 146 * Collects all the data to display in the resource status dialog.<p> 147 * 148 * @param cms the current CMS context 149 * @param structureId the structure id of the resource for which we want the information 150 * @param contentLocale the content locale 151 * @param includeTargets true if relation targets should be included 152 * @param additionalStructureIds structure ids of additional resources to include with the relation targets 153 * 154 * @return the resource status information 155 * @throws CmsException if something goes wrong 156 */ 157 public CmsResourceStatusBean getResourceStatus( 158 CmsObject cms, 159 CmsUUID structureId, 160 String contentLocale, 161 boolean includeTargets, 162 List<CmsUUID> additionalStructureIds) throws CmsException { 163 164 Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms); 165 cms.getRequestContext().setLocale(locale); 166 CmsResource resource = cms.readResource(structureId, CmsResourceFilter.ALL); 167 String localizedTitle = null; 168 if (!CmsStringUtil.isEmptyOrWhitespaceOnly(contentLocale)) { 169 Locale realLocale = CmsLocaleManager.getLocale(contentLocale); 170 CmsGallerySearchResult result = CmsGallerySearch.searchById(cms, structureId, realLocale); 171 if (!CmsStringUtil.isEmptyOrWhitespaceOnly(result.getTitle())) { 172 localizedTitle = result.getTitle(); 173 } 174 } 175 CmsResourceUtil resourceUtil = new CmsResourceUtil(cms, resource); 176 List<CmsProperty> properties = cms.readPropertyObjects(resource, false); 177 CmsResourceStatusBean result = new CmsResourceStatusBean(); 178 result.setDateCreated(CmsVfsService.formatDateTime(cms, resource.getDateCreated())); 179 long dateExpired = resource.getDateExpired(); 180 if (dateExpired != CmsResource.DATE_EXPIRED_DEFAULT) { 181 result.setDateExpired(CmsVfsService.formatDateTime(cms, dateExpired)); 182 } 183 result.setDateLastModified(CmsVfsService.formatDateTime(cms, resource.getDateLastModified())); 184 long dateReleased = resource.getDateReleased(); 185 if (dateReleased != CmsResource.DATE_RELEASED_DEFAULT) { 186 result.setDateReleased(CmsVfsService.formatDateTime(cms, dateReleased)); 187 } 188 String lastProject = resourceUtil.getLockedInProjectName(); 189 if ("".equals(lastProject)) { 190 lastProject = null; 191 } 192 result.setLastProject(lastProject); 193 194 result.setListInfo(CmsVfsService.getPageInfo(cms, resource)); 195 CmsLock lock = cms.getLock(resource); 196 CmsUser lockOwner = null; 197 if (!lock.isUnlocked()) { 198 lockOwner = cms.readUser(lock.getUserId()); 199 result.setLockState( 200 org.opencms.workplace.list.Messages.get().getBundle(locale).key( 201 org.opencms.workplace.list.Messages.GUI_EXPLORER_LIST_ACTION_LOCK_NAME_2, 202 lockOwner.getName(), 203 lastProject)); 204 } else { 205 result.setLockState( 206 org.opencms.workplace.list.Messages.get().getBundle(locale).key( 207 org.opencms.workplace.list.Messages.GUI_EXPLORER_LIST_ACTION_UNLOCK_NAME_0)); 208 } 209 210 CmsProperty navText = CmsProperty.get(CmsPropertyDefinition.PROPERTY_NAVTEXT, properties); 211 if (navText != null) { 212 result.setNavText(navText.getValue()); 213 } 214 result.setPermissions(resourceUtil.getPermissionString()); 215 result.setSize(resource.getLength()); 216 result.setStateBean(resource.getState()); 217 CmsProperty title = CmsProperty.get(CmsPropertyDefinition.PROPERTY_TITLE, properties); 218 if (localizedTitle != null) { 219 result.setTitle(localizedTitle); 220 result.getListInfo().setTitle(localizedTitle); 221 } else if (title != null) { 222 result.setTitle(title.getValue()); 223 } 224 result.setUserCreated(resourceUtil.getUserCreated()); 225 result.setUserLastModified(resourceUtil.getUserLastModified()); 226 227 I_CmsResourceType resType = OpenCms.getResourceManager().getResourceType(resource.getTypeId()); 228 result.setResourceType(resType.getTypeName()); 229 result.setStructureId(resource.getStructureId()); 230 if (resType instanceof CmsResourceTypeXmlContent) { 231 CmsFile file = cms.readFile(resource); 232 CmsXmlContent content = CmsXmlContentFactory.unmarshal(cms, file); 233 List<Locale> locales = content.getLocales(); 234 List<String> localeStrings = new ArrayList<String>(); 235 for (Locale l : locales) { 236 localeStrings.add(l.toString()); 237 } 238 result.setLocales(localeStrings); 239 } 240 241 List<CmsRelation> relations = cms.readRelations( 242 CmsRelationFilter.relationsToStructureId(resource.getStructureId())); 243 Map<CmsUUID, CmsResource> relationSources = new HashMap<CmsUUID, CmsResource>(); 244 245 if (CmsResourceTypeXmlContainerPage.isContainerPage(resource)) { 246 // People may link to the folder of a container page instead of the page itself 247 try { 248 CmsResource parent = cms.readParentFolder(resource.getStructureId()); 249 List<CmsRelation> parentRelations = cms.readRelations( 250 CmsRelationFilter.relationsToStructureId(parent.getStructureId())); 251 relations.addAll(parentRelations); 252 } catch (CmsException e) { 253 LOG.error(e.getLocalizedMessage(), e); 254 } 255 } 256 257 // find all distinct relation sources 258 for (CmsRelation relation : relations) { 259 try { 260 CmsResource currentSource = relation.getSource(cms, CmsResourceFilter.ALL); 261 relationSources.put(currentSource.getStructureId(), currentSource); 262 } catch (CmsException e) { 263 LOG.error(e.getLocalizedMessage(), e); 264 } 265 } 266 267 for (CmsResource relationResource : relationSources.values()) { 268 try { 269 CmsPermissionInfo permissionInfo = OpenCms.getADEManager().getPermissionInfo( 270 cms, 271 relationResource, 272 resource.getRootPath()); 273 if (permissionInfo.hasViewPermission()) { 274 CmsResourceStatusRelationBean relationBean = createRelationBean( 275 cms, 276 contentLocale, 277 relationResource, 278 permissionInfo); 279 CmsSite site = OpenCms.getSiteManager().getSiteForRootPath(relationResource.getRootPath()); 280 if ((site != null) 281 && !CmsStringUtil.isPrefixPath( 282 cms.getRequestContext().getSiteRoot(), 283 relationResource.getRootPath())) { 284 String siteTitle = site.getTitle(); 285 if (siteTitle == null) { 286 siteTitle = site.getUrl(); 287 } else { 288 siteTitle = CmsWorkplace.substituteSiteTitleStatic( 289 siteTitle, 290 OpenCms.getWorkplaceManager().getWorkplaceLocale(cms)); 291 } 292 relationBean.setSiteRoot(site.getSiteRoot()); 293 result.getOtherSiteRelationSources().add(relationBean); 294 relationBean.getInfoBean().setTitle( 295 "[" + siteTitle + "] " + relationBean.getInfoBean().getTitle()); 296 } else { 297 result.getRelationSources().add(relationBean); 298 } 299 300 } 301 } catch (CmsVfsResourceNotFoundException notfound) { 302 LOG.error(notfound.getLocalizedMessage(), notfound); 303 continue; 304 } 305 } 306 sortOtherSiteRelations(cms, result); 307 if (includeTargets) { 308 result.getRelationTargets().addAll(getTargets(cms, contentLocale, resource, additionalStructureIds)); 309 } 310 result.getSiblings().addAll(getSiblings(cms, contentLocale, resource)); 311 LinkedHashMap<CmsResourceStatusTabId, String> tabMap = new LinkedHashMap<CmsResourceStatusTabId, String>(); 312 Map<CmsResourceStatusTabId, CmsMessageContainer> tabs; 313 CmsResourceStatusTabId startTab = CmsResourceStatusTabId.tabRelationsFrom; 314 if (CmsResourceTypeXmlContainerPage.isContainerPage(resource)) { 315 tabs = CmsResourceStatusConstants.STATUS_TABS_CONTAINER_PAGE; 316 } else if (OpenCms.getResourceManager().getResourceType(resource) instanceof I_CmsLinkParseable) { 317 tabs = CmsResourceStatusConstants.STATUS_TABS_CONTENT; 318 } else { 319 tabs = CmsResourceStatusConstants.STATUS_TABS_OTHER; 320 startTab = CmsResourceStatusTabId.tabStatus; 321 } 322 for (Map.Entry<CmsResourceStatusTabId, CmsMessageContainer> entry : tabs.entrySet()) { 323 tabMap.put(entry.getKey(), entry.getValue().key(locale)); 324 } 325 326 result.setTabs(tabMap); 327 result.setStartTab(startTab); 328 return result; 329 } 330 331 /** 332 * Sorts relation beans from other sites by site order.<p> 333 * 334 * @param cms the current CMS context 335 * @param resStatus the bean in which to sort the relation beans 336 */ 337 public void sortOtherSiteRelations(CmsObject cms, CmsResourceStatusBean resStatus) { 338 339 final List<CmsSite> sites = OpenCms.getSiteManager().getAvailableSites( 340 cms, 341 false, 342 false, 343 cms.getRequestContext().getOuFqn()); 344 Collections.sort(resStatus.getOtherSiteRelationSources(), new Comparator<CmsResourceStatusRelationBean>() { 345 346 private Map<String, Integer> m_rankCache = Maps.newHashMap(); 347 348 public int compare(CmsResourceStatusRelationBean o1, CmsResourceStatusRelationBean o2) { 349 350 return ComparisonChain.start().compare(rank(o1), rank(o2)).compare( 351 o1.getSitePath(), 352 o2.getSitePath()).result(); 353 354 } 355 356 public int rank(CmsResourceStatusRelationBean r) { 357 358 if (m_rankCache.containsKey(r.getSiteRoot())) { 359 return m_rankCache.get(r.getSiteRoot()).intValue(); 360 } 361 362 int j = 0; 363 int result = Integer.MAX_VALUE; 364 for (CmsSite site : sites) { 365 if (site.getSiteRoot().equals(r.getSiteRoot())) { 366 result = j; 367 break; 368 } 369 j += 1; 370 } 371 372 m_rankCache.put(r.getSiteRoot(), new Integer(result)); 373 return result; 374 } 375 }); 376 } 377 378 /** 379 * Gets beans which represents the siblings of a resource.<p> 380 * 381 * @param cms the CMS ccontext 382 * @param locale the locale 383 * @param resource the resource 384 * @return the list of sibling beans 385 * 386 * @throws CmsException if something goes wrong 387 */ 388 protected List<CmsResourceStatusRelationBean> getSiblings(CmsObject cms, String locale, CmsResource resource) 389 throws CmsException { 390 391 List<CmsResourceStatusRelationBean> result = new ArrayList<CmsResourceStatusRelationBean>(); 392 for (CmsResource sibling : cms.readSiblings(resource, CmsResourceFilter.ALL)) { 393 if (sibling.getStructureId().equals(resource.getStructureId())) { 394 continue; 395 } 396 try { 397 CmsPermissionInfo permissionInfo = OpenCms.getADEManager().getPermissionInfo( 398 cms, 399 sibling, 400 resource.getRootPath()); 401 if (permissionInfo.hasViewPermission()) { 402 CmsResourceStatusRelationBean relationBean = createRelationBean( 403 cms, 404 locale, 405 sibling, 406 permissionInfo); 407 result.add(relationBean); 408 } 409 } catch (CmsException e) { 410 LOG.error(e.getLocalizedMessage(), e); 411 } 412 } 413 return result; 414 } 415 416 /** 417 * Gets the list of relation targets for a resource.<p> 418 * 419 * @param cms the current CMS context 420 * @param locale the locale 421 * @param resource the resource for which we want the relation targets 422 * @param additionalStructureIds structure ids of additional resources to include with the relation target 423 * 424 * @return the list of relation beans for the relation targets 425 * 426 * @throws CmsException if something goes wrong 427 */ 428 protected List<CmsResourceStatusRelationBean> getTargets( 429 CmsObject cms, 430 String locale, 431 CmsResource resource, 432 List<CmsUUID> additionalStructureIds) throws CmsException { 433 434 CmsRelationTargetListBean listBean = getContainerpageRelationTargets( 435 cms, 436 resource.getStructureId(), 437 additionalStructureIds, 438 false); 439 List<CmsResourceStatusRelationBean> result = new ArrayList<CmsResourceStatusRelationBean>(); 440 for (CmsResource target : listBean.getResources()) { 441 try { 442 CmsPermissionInfo permissionInfo = OpenCms.getADEManager().getPermissionInfo( 443 cms, 444 target, 445 resource.getRootPath()); 446 if (permissionInfo.hasViewPermission()) { 447 CmsResourceStatusRelationBean relationBean = createRelationBean( 448 cms, 449 locale, 450 target, 451 permissionInfo); 452 result.add(relationBean); 453 } 454 } catch (CmsException e) { 455 LOG.error(e.getLocalizedMessage(), e); 456 } 457 } 458 return result; 459 460 } 461 462 /** 463 * Creates a bean for a single resource which is part of a relation list.<p> 464 * 465 * @param cms the current CMS context 466 * @param locale the locale 467 * @param relationResource the resource 468 * @param permissionInfo the permission info 469 * 470 * @return the status bean for the resource 471 * 472 * @throws CmsException if something goes wrong 473 */ 474 CmsResourceStatusRelationBean createRelationBean( 475 CmsObject cms, 476 String locale, 477 CmsResource relationResource, 478 CmsPermissionInfo permissionInfo) throws CmsException { 479 480 CmsListInfoBean sourceBean = CmsVfsService.getPageInfo(cms, relationResource); 481 sourceBean.setMarkChangedState(true); 482 sourceBean.setResourceState(relationResource.getState()); 483 484 if (!CmsStringUtil.isEmptyOrWhitespaceOnly(locale)) { 485 Locale realLocale = CmsLocaleManager.getLocale(locale); 486 CmsGallerySearchResult result = CmsGallerySearch.searchById( 487 cms, 488 relationResource.getStructureId(), 489 realLocale); 490 if (!CmsStringUtil.isEmptyOrWhitespaceOnly(result.getTitle())) { 491 sourceBean.setTitle(result.getTitle()); 492 } 493 } 494 String link = null; 495 try { 496 link = OpenCms.getLinkManager().substituteLink(cms, relationResource); 497 } catch (Exception e) { 498 LOG.warn(e.getLocalizedMessage(), e); 499 } 500 CmsResourceStatusRelationBean relationBean = new CmsResourceStatusRelationBean( 501 sourceBean, 502 link, 503 relationResource.getStructureId(), 504 permissionInfo); 505 if (CmsResourceTypeXmlContent.isXmlContent(relationResource)) { 506 relationBean.setIsXmlContent(true); 507 } 508 String sitePath = cms.getSitePath(relationResource); 509 relationBean.setSitePath(sitePath); 510 return relationBean; 511 } 512 513}