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