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.file.collectors; 029 030import org.opencms.db.CmsDbEntryNotFoundException; 031import org.opencms.file.CmsObject; 032import org.opencms.file.CmsProperty; 033import org.opencms.file.CmsResource; 034import org.opencms.main.CmsException; 035import org.opencms.main.CmsIllegalArgumentException; 036import org.opencms.util.CmsStringUtil; 037import org.opencms.util.CmsUUID; 038 039import java.io.Serializable; 040import java.text.Collator; 041import java.text.NumberFormat; 042import java.text.ParsePosition; 043import java.util.Comparator; 044import java.util.HashMap; 045import java.util.Map; 046 047/** 048 * Comparator for sorting resource objects based on a selected property value.<p> 049 * 050 * Serves as {@link java.util.Comparator} for resources and as comparator key for the resource 051 * at the same time. Uses lazy initializing of comparator keys in a resource.<p> 052 * 053 * @since 8.0.4 054 */ 055public class CmsPropertyResourceComparator implements Serializable, Comparator<CmsResource> { 056 057 /** Serial version UID required for safe serialization. */ 058 private static final long serialVersionUID = -7943213182160054552L; 059 060 /** The sort order. */ 061 private boolean m_asc; 062 063 /** The current OpenCms user context. */ 064 private transient CmsObject m_cms; 065 066 /** The internal map of comparator keys. */ 067 private Map<CmsUUID, CmsPropertyResourceComparator> m_keys; 068 069 /** The property name of this comparator key. */ 070 private String m_property; 071 072 /** The property value of this comparator key. */ 073 private String m_propertyValue; 074 075 /** 076 * Creates a new instance of this comparator key.<p> 077 * 078 * @param cms the current OpenCms user context 079 * @param property the name of the sort property (case sensitive) 080 * @param asc the sort order (true=asc, false=desc) 081 */ 082 public CmsPropertyResourceComparator(CmsObject cms, String property, boolean asc) { 083 084 m_property = property; 085 m_asc = asc; 086 m_cms = cms; 087 m_keys = new HashMap<CmsUUID, CmsPropertyResourceComparator>(); 088 } 089 090 /** 091 * Creates a new instance of this comparator key.<p> 092 * 093 * @param resource the resource to create the key for 094 * @param cms the current OpenCms user context 095 * @param property the name of the sort property (case sensitive) 096 * 097 * @return a new instance of this comparator key 098 */ 099 private static CmsPropertyResourceComparator create(CmsResource resource, CmsObject cms, String property) { 100 101 CmsPropertyResourceComparator result = new CmsPropertyResourceComparator(null, null, false); 102 result.init(resource, cms, property); 103 return result; 104 } 105 106 /** 107 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) 108 */ 109 public int compare(CmsResource res0, CmsResource res1) { 110 111 if (res0 == res1) { 112 return 0; 113 } 114 115 CmsPropertyResourceComparator key0 = m_keys.get(res0.getStructureId()); 116 CmsPropertyResourceComparator key1 = m_keys.get(res1.getStructureId()); 117 118 if (key0 == null) { 119 // initialize key if null 120 key0 = CmsPropertyResourceComparator.create(res0, m_cms, m_property); 121 m_keys.put(res0.getStructureId(), key0); 122 } 123 if (key1 == null) { 124 // initialize key if null 125 key1 = CmsPropertyResourceComparator.create(res1, m_cms, m_property); 126 m_keys.put(res1.getStructureId(), key1); 127 } 128 129 // select a different sort methode for strings or number values 130 if (isNumeric(key0.getPropertyValue()) && isNumeric(key1.getPropertyValue())) { 131 // double can do it all.... ;-) 132 double dKey0 = Double.parseDouble(key0.getPropertyValue()); 133 double dKey1 = Double.parseDouble(key1.getPropertyValue()); 134 135 if (m_asc) { 136 // sort in ascending order 137 if (dKey0 > dKey1) { 138 return 1; 139 } 140 if (dKey0 < dKey1) { 141 return -1; 142 } 143 } else { 144 // sort in descending order 145 if (dKey0 > dKey1) { 146 return -1; 147 } 148 if (dKey0 < dKey1) { 149 return 1; 150 } 151 } 152 153 } else { 154 // sort by property value depending on the locale 155 Collator collator = Collator.getInstance(m_cms.getRequestContext().getLocale()); 156 if (m_asc) { 157 // sort in ascending order 158 return collator.compare(key0.getPropertyValue(), key1.getPropertyValue()); 159 } else { 160 // sort in descending order 161 return collator.compare(key1.getPropertyValue(), key0.getPropertyValue()); 162 } 163 } 164 return 0; 165 } 166 167 /** 168 * Returns the property value of this resource comparator key.<p> 169 * 170 * @return property value of this resource comparator key 171 */ 172 public String getPropertyValue() { 173 174 if (!CmsStringUtil.isEmpty(m_propertyValue)) { 175 return m_propertyValue.trim(); 176 } else { 177 return ""; 178 } 179 } 180 181 /** 182 * Initializes the comparator key based on the member variables.<p> 183 * 184 * @param resource the resource to use 185 * @param cms the current OpenCms user contxt 186 * @param property the name of the sort property (case sensitive) 187 */ 188 private void init(CmsResource resource, CmsObject cms, String property) { 189 190 try { 191 cms.readPropertyDefinition(property); 192 CmsProperty prop = cms.readPropertyObject(resource, property, false); 193 194 if (prop == CmsProperty.getNullProperty()) { 195 m_propertyValue = ""; 196 } else { 197 m_propertyValue = prop.getValue(); 198 } 199 } catch (CmsDbEntryNotFoundException dbe) { 200 // property are not configured 201 throw new CmsIllegalArgumentException( 202 Messages.get().container(Messages.ERR_COLLECTOR_PARAM_PROPERTY_NOT_FOUND_1, property)); 203 } catch (CmsException cmse) { 204 // something's gone wrong... 205 cmse.printStackTrace(); 206 } 207 } 208 209 /** 210 * Check if a string contains a numeric value.<p> 211 * 212 * @param value string to check if is a numeric value 213 * 214 * @return true for a numeric value in the string 215 */ 216 private boolean isNumeric(String value) { 217 218 if (!CmsStringUtil.isEmpty(value)) { 219 NumberFormat formatter = NumberFormat.getInstance(); 220 ParsePosition pos = new ParsePosition(0); 221 formatter.parse(value, pos); 222 return value.length() == pos.getIndex(); 223 } else { 224 return false; 225 } 226 } 227 228}