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.search.fields; 029 030import org.opencms.file.CmsObject; 031import org.opencms.file.CmsProperty; 032import org.opencms.file.CmsResource; 033import org.opencms.file.CmsVfsResourceNotFoundException; 034import org.opencms.main.CmsLog; 035import org.opencms.main.OpenCms; 036import org.opencms.search.I_CmsSearchIndex; 037import org.opencms.search.extractors.CmsExtractionResult; 038import org.opencms.search.extractors.I_CmsExtractionResult; 039import org.opencms.search.solr.CmsSolrDocumentXmlContent; 040import org.opencms.search.solr.CmsSolrIndex; 041import org.opencms.util.CmsGeoUtil; 042import org.opencms.util.CmsStringUtil; 043import org.opencms.xml.A_CmsXmlDocument; 044import org.opencms.xml.CmsXmlUtils; 045import org.opencms.xml.content.CmsGeoMappingConfiguration; 046import org.opencms.xml.content.I_CmsXmlContentHandler; 047 048import java.util.HashSet; 049import java.util.List; 050import java.util.Locale; 051import java.util.Set; 052 053import org.apache.commons.logging.Log; 054 055/** 056 * Class extracting the Geo coordinates from a content field. 057 */ 058public class CmsGeoCoordinateFieldMapping implements I_CmsSearchFieldMapping { 059 060 /** The log object for this class. */ 061 private static final Log LOG = CmsLog.getLog(CmsGeoCoordinateFieldMapping.class); 062 063 /** Serial version UID. */ 064 private static final long serialVersionUID = 1; 065 066 /** Maximum recursion depth for following links. */ 067 public static final int MAX_DEPTH = 2; 068 069 /** The geo-mapping configuration. */ 070 private CmsGeoMappingConfiguration m_config; 071 072 /** 073 * Creates a new instance. 074 * 075 * @param config the configuration to use 076 */ 077 public CmsGeoCoordinateFieldMapping(CmsGeoMappingConfiguration config) { 078 079 m_config = config; 080 } 081 082 /** 083 * @see org.opencms.search.fields.I_CmsSearchFieldMapping#getDefaultValue() 084 */ 085 public String getDefaultValue() { 086 087 return "0.000000,0.000000"; 088 } 089 090 /** 091 * @see org.opencms.search.fields.I_CmsSearchFieldMapping#getParam() 092 */ 093 public String getParam() { 094 095 return ""; 096 } 097 098 /** 099 * @see org.opencms.search.fields.I_CmsSearchFieldMapping#getStringValue(org.opencms.file.CmsObject, org.opencms.file.CmsResource, org.opencms.search.extractors.I_CmsExtractionResult, java.util.List, java.util.List) 100 */ 101 public String getStringValue( 102 CmsObject cms, 103 CmsResource res, 104 I_CmsExtractionResult extractionResult, 105 List<CmsProperty> properties, 106 List<CmsProperty> propertiesSearched) { 107 108 String result = getStringValue(0, m_config, cms, res, extractionResult); 109 return result; 110 } 111 112 /** 113 * Gets the mapped value. 114 * 115 * @param depth the current recursion depth 116 * @param mappingConfig the mapping configuration to use 117 * @param cms the CMS context 118 * @param res the resource for which to get the value 119 * @param extractionResult the extraction result of the resource 120 * 121 * @return the mapped value 122 */ 123 public String getStringValue( 124 int depth, 125 CmsGeoMappingConfiguration mappingConfig, 126 CmsObject cms, 127 CmsResource res, 128 I_CmsExtractionResult extractionResult) { 129 130 for (CmsGeoMappingConfiguration.Entry entry : mappingConfig.getEntries()) { 131 try { 132 switch (entry.getType()) { 133 case field: 134 String value = findFirstCoordinatesValue(extractionResult, entry.getValue()); 135 String coord = CmsGeoUtil.parseCoordinates(value); 136 if (coord != null) { 137 return coord; 138 } 139 break; 140 case link: 141 if (depth >= MAX_DEPTH) { 142 LOG.error( 143 "maximum depth exceeded for linked geo-coordinate mapping in " + res.getRootPath()); 144 return null; 145 } 146 String xpath = CmsXmlUtils.createXpath(entry.getValue(), 1); 147 Set<String> paths = new HashSet<>(); 148 for (Locale locale : extractionResult.getLocales()) { 149 String path = extractionResult.getContentItems(locale).get(xpath); 150 if (path != null) { 151 paths.add(path); 152 } 153 } 154 I_CmsSearchIndex index = OpenCms.getSearchManager().getIndex( 155 cms.getRequestContext().getCurrentProject().isOnlineProject() 156 ? CmsSolrIndex.DEFAULT_INDEX_NAME_ONLINE 157 : CmsSolrIndex.DEFAULT_INDEX_NAME_OFFLINE); 158 159 for (String path : paths) { 160 try { 161 CmsResource linkedResource = cms.readResource(path); 162 A_CmsXmlDocument[] contentHolder = new A_CmsXmlDocument[] {null}; 163 CmsExtractionResult linkExtractionResult = CmsSolrDocumentXmlContent.extractXmlContent( 164 cms, 165 linkedResource, 166 index, 167 null, 168 new HashSet<>(), 169 content -> { 170 contentHolder[0] = content; 171 }); 172 if ((linkExtractionResult != null) && (contentHolder[0] != null)) { 173 I_CmsXmlContentHandler linkContentHandler = contentHolder[0].getContentDefinition().getContentHandler(); 174 CmsGeoMappingConfiguration linkMappingConfig = linkContentHandler.getGeoMappingConfiguration(); 175 if (linkMappingConfig != null) { 176 String linkResult = getStringValue( 177 depth + 1, 178 linkMappingConfig, 179 cms, 180 contentHolder[0].getFile(), 181 linkExtractionResult); 182 if (linkResult != null) { 183 return linkResult; 184 } 185 } 186 } 187 } catch (CmsVfsResourceNotFoundException e) { 188 LOG.debug(e.getLocalizedMessage(), e); 189 } catch (Exception e) { 190 LOG.error(e.getLocalizedMessage(), e); 191 } 192 } 193 break; 194 default: 195 break; 196 } 197 } catch (Exception e) { 198 LOG.error(e.getLocalizedMessage(), e); 199 } 200 } 201 return null; 202 } 203 204 /** 205 * @see org.opencms.search.fields.I_CmsSearchFieldMapping#getType() 206 */ 207 public CmsSearchFieldMappingType getType() { 208 209 return CmsSearchFieldMappingType.ITEM; 210 } 211 212 /** 213 * @see org.opencms.search.fields.I_CmsSearchFieldMapping#setDefaultValue(java.lang.String) 214 */ 215 public void setDefaultValue(String defaultValue) { 216 217 // not used 218 } 219 220 /** 221 * @see org.opencms.search.fields.I_CmsSearchFieldMapping#setParam(java.lang.String) 222 */ 223 public void setParam(String param) { 224 225 // not used 226 } 227 228 /** 229 * @see org.opencms.search.fields.I_CmsSearchFieldMapping#setType(org.opencms.search.fields.CmsSearchFieldMappingType) 230 */ 231 public void setType(CmsSearchFieldMappingType type) { 232 233 // not used 234 } 235 236 /** 237 * @see org.opencms.search.fields.I_CmsSearchFieldMapping#setType(java.lang.String) 238 */ 239 public void setType(String type) { 240 241 // not used 242 } 243 244 /** 245 * At first, we search for a coordinates value in the best matching locale of the extraction 246 * result. If not available, search for a coordinates value in other locales. In the case of 247 * a multi-valued field, only the first coordinates value is returned. Further values are ignored. 248 * 249 * @param xpath the path to look up in the extraction result 250 * @param extractionResult the extraction result 251 * @return the coordinates value 252 */ 253 private String findFirstCoordinatesValue(I_CmsExtractionResult extractionResult, String xpath) { 254 255 xpath = CmsXmlUtils.createXpath(xpath, 1); 256 String value = extractionResult.getContentItems().get(xpath); 257 if (CmsStringUtil.isEmptyOrWhitespaceOnly(value)) { 258 for (Locale locale : extractionResult.getLocales()) { 259 String val = extractionResult.getContentItems(locale).get(xpath); 260 if (!CmsStringUtil.isEmptyOrWhitespaceOnly(val)) { 261 return val; 262 } 263 } 264 } 265 return value; 266 } 267 268}