001/* 002 * (C) Copyright 2010-2013 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Olivier Grisel 016 */ 017package org.nuxeo.ecm.platform.suggestbox.service.descriptors; 018 019import java.util.ArrayList; 020import java.util.Iterator; 021import java.util.List; 022 023import org.apache.commons.logging.Log; 024import org.apache.commons.logging.LogFactory; 025import org.nuxeo.common.xmap.annotation.XNode; 026import org.nuxeo.common.xmap.annotation.XNodeList; 027import org.nuxeo.common.xmap.annotation.XObject; 028import org.nuxeo.ecm.platform.suggestbox.service.ComponentInitializationException; 029 030@XObject("suggesterGroup") 031public class SuggesterGroupDescriptor implements Cloneable { 032 033 private static final Log log = LogFactory.getLog(SuggesterGroupDescriptor.class); 034 035 @XNode("@name") 036 protected String name = "default"; 037 038 @XNodeList(value = "suggesters/suggesterName", type = ArrayList.class, componentType = SuggesterGroupItemDescriptor.class) 039 List<SuggesterGroupItemDescriptor> suggesters; 040 041 public String getName() { 042 return name; 043 } 044 045 public List<SuggesterGroupItemDescriptor> getSuggesters() { 046 return suggesters; 047 } 048 049 public void mergeFrom(SuggesterGroupDescriptor newDescriptor) throws ComponentInitializationException { 050 if (name == null || !name.equals(newDescriptor.name)) { 051 throw new RuntimeException("Cannot merge descriptor with name '" + name 052 + "' with another descriptor with different name " + newDescriptor.getName() + "'"); 053 } 054 log.info(String.format("Merging suggester group '%s'.", name)); 055 // merge the suggesterNames 056 for (SuggesterGroupItemDescriptor newSuggesterGroupItem : newDescriptor.getSuggesters()) { 057 String newSuggesterName = newSuggesterGroupItem.getName(); 058 // manage remove 059 if (newSuggesterGroupItem.isRemove()) { 060 boolean isSuggesterRemoved = remove(newSuggesterName); 061 if (!isSuggesterRemoved) { 062 log.warn(String.format( 063 "Cannot remove suggester '%s' because it does not exist in suggesterGroup '%s'.", 064 newSuggesterName, name)); 065 } 066 } 067 // manage appendBefore, appendAfter or no particular attributes 068 else { 069 String appendBeforeSuggesterName = newSuggesterGroupItem.getAppendBefore(); 070 String appendAfterSuggesterName = newSuggesterGroupItem.getAppendAfter(); 071 // can't have both appendBefore and appendAfter 072 if (appendBeforeSuggesterName != null && appendAfterSuggesterName != null) { 073 throw new RuntimeException(String.format( 074 "Cannot define both 'appendBefore' and 'appendAfter' attributes on suggester '%s'.", 075 newSuggesterName)); 076 } 077 // manage appendBefore 078 if (appendBeforeSuggesterName != null) { 079 boolean isSuggesterAppended = appendBefore(appendBeforeSuggesterName, newSuggesterName); 080 if (!isSuggesterAppended) { 081 logExistingSuggesterName(newSuggesterName); 082 } 083 } 084 // manage appendAfter 085 else if (appendAfterSuggesterName != null) { 086 boolean isSuggesterAppended = appendAfter(appendAfterSuggesterName, newSuggesterName); 087 if (!isSuggesterAppended) { 088 logExistingSuggesterName(newSuggesterName); 089 } 090 } 091 // manage the case of no particular attributes => append 092 // suggester at the end of the list 093 else if (appendBeforeSuggesterName == null && appendAfterSuggesterName == null) { 094 boolean isSuggesterAppended = appendAfter(null, newSuggesterName); 095 if (!isSuggesterAppended) { 096 logExistingSuggesterName(newSuggesterName); 097 } 098 } 099 } 100 } 101 } 102 103 /* 104 * Override the Object.clone to make it public 105 */ 106 @Override 107 public Object clone() throws CloneNotSupportedException { 108 return super.clone(); 109 } 110 111 /** 112 * Removes the suggester named {@code suggesterName} from the {@code #suggesters} list. 113 * 114 * @param suggesterName the suggester name 115 * @return true, if a suggester was removed 116 */ 117 protected boolean remove(String suggesterName) { 118 Iterator<SuggesterGroupItemDescriptor> suggestersIt = suggesters.iterator(); 119 while (suggestersIt.hasNext()) { 120 SuggesterGroupItemDescriptor suggesterGroupItem = suggestersIt.next(); 121 if (suggesterName.equals(suggesterGroupItem.getName())) { 122 suggestersIt.remove(); 123 log.debug(String.format("Removed suggester '%s' from suggesterGroup '%s'.", suggesterName, name)); 124 return true; 125 } 126 } 127 return false; 128 } 129 130 /** 131 * Returns the index of the first occurrence of the element named {@code suggesterName} in the {@code #suggesters} 132 * list, or -1 if {@code suggesterName} is null or if this list does not contain the element. 133 * 134 * @param suggesterName the suggester name 135 * @return the index of the first occurrence of the element named {@code suggesterName} in the {@code #suggesters} 136 * list, or -1 if {@code suggesterName} is null or if this list does not contain the element 137 */ 138 protected int indexOf(String suggesterName) { 139 if (suggesterName != null) { 140 int index = 0; 141 Iterator<SuggesterGroupItemDescriptor> suggestersIt = suggesters.iterator(); 142 while (suggestersIt.hasNext()) { 143 SuggesterGroupItemDescriptor suggesterGroupItem = suggestersIt.next(); 144 if (suggesterName.equals(suggesterGroupItem.getName())) { 145 return index; 146 } 147 index++; 148 } 149 } 150 return -1; 151 } 152 153 /** 154 * Unless a suggester named {@code newSuggesterName} already exists in the {@code #suggesters} list, appends a new 155 * {@code SuggesterGroupItemDescriptor} named {@code newSuggesterName} just before the suggester named 156 * {@code suggesterName} in the {@code #suggesters} list. If the suggester named {@code suggesterName} does not 157 * exist, appends the new suggester at the beginning of the list. 158 * 159 * @param suggesterName the suggester name 160 * @param newSuggesterName the name of the suggester to append 161 * @return true, if the suggester named {@code newSuggesterName} was appended to the {@code #suggesters} list 162 */ 163 protected boolean appendBefore(String suggesterName, String newSuggesterName) { 164 return append(suggesterName, newSuggesterName, true); 165 } 166 167 /** 168 * Unless a suggester named {@code newSuggesterName} already exists in the {@code #suggesters} list, appends a new 169 * {@code SuggesterGroupItemDescriptor} named {@code newSuggesterName} just after the suggester named 170 * {@code suggesterName} in the {@code #suggesters} list. If the suggester named {@code suggesterName} does not 171 * exist, appends the new suggester at the end of the list. 172 * 173 * @param suggesterName the suggester name 174 * @param newSuggesterName the name of the suggester to append 175 * @return true, if the suggester named {@code newSuggesterName} was appended to the {@code #suggesters} list 176 */ 177 protected boolean appendAfter(String suggesterName, String newSuggesterName) { 178 return append(suggesterName, newSuggesterName, false); 179 } 180 181 /** 182 * Unless a suggester named {@code newSuggesterName} already exists in the {@code #suggesters} list, appends a new 183 * {@code SuggesterGroupItemDescriptor} named {@code newSuggesterName} just before (if {@code before} is true) or 184 * after the suggester named {@code suggesterName} in the {@code #suggesters} list. If the suggester named 185 * {@code suggesterName} does not exist, appends the new suggester at the beginning or the end of the list, 186 * depending on {@code before}. 187 * 188 * @param suggesterName the suggester name 189 * @param newSuggesterName the name of the suggester to append 190 * @return true, if the suggester named {@code newSuggesterName} was appended to the {@code #suggesters} list 191 */ 192 protected boolean append(String suggesterName, String newSuggesterName, boolean before) { 193 // check if the new suggester's name doesn't already exist in the 194 // suggesters list 195 if (indexOf(newSuggesterName) > -1) { 196 return false; 197 } 198 // new suggester 199 SuggesterGroupItemDescriptor newSuggester = new SuggesterGroupItemDescriptor(newSuggesterName); 200 int indexOfSuggester = indexOf(suggesterName); 201 if (indexOfSuggester > -1) { 202 // suggester found, append new suggester before or after it 203 int indexOfNewSuggester = before ? indexOfSuggester : indexOfSuggester + 1; 204 suggesters.add(indexOfNewSuggester, newSuggester); 205 log.debug(String.format("Appended suggester '%s' %s suggester '%s' in suggesterGroup '%s'.", 206 newSuggesterName, before ? "before" : "after", suggesterName, name)); 207 } else { 208 // suggester not found, append new suggester at the beginning or the 209 // end of the suggesters list 210 if (before) { 211 suggesters.add(0, newSuggester); 212 if (suggesterName != null) { 213 log.warn(String.format( 214 "Could not append suggester '%s' before suggester '%s' in suggesterGroup '%s' because '%s' does not exist in this suggesterGroup. Appended it before all suggesters.", 215 newSuggesterName, suggesterName, name, suggesterName)); 216 } 217 } else { 218 suggesters.add(newSuggester); 219 if (suggesterName != null) { 220 log.warn(String.format( 221 "Could not append suggester '%s' after suggester '%s' in suggesterGroup '%s' because '%s' does not exist in this suggesterGroup. Appended it after all suggesters.", 222 newSuggesterName, suggesterName, name, suggesterName)); 223 } 224 } 225 } 226 return true; 227 } 228 229 /** 230 * Logs that the suggester named {@code newSuggesterName} already exists in the {@code #suggesters} list and 231 * therefore won't be appended to it. 232 * 233 * @param newSuggesterName the new suggester name 234 */ 235 protected void logExistingSuggesterName(String newSuggesterName) { 236 log.warn(String.format( 237 "Suggester '%s' already exists in suggesterGroup '%s'. Cannot have two occurrences of the same suggester, so won't append it.", 238 newSuggesterName, name)); 239 } 240}