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