1 16 package org.outerj.daisy.frontend; 17 18 import org.outerj.daisy.frontend.util.AbstractDaisyApple; 19 import org.outerj.daisy.frontend.util.XmlObjectXMLizable; 20 import org.outerj.daisy.frontend.components.siteconf.SiteConf; 21 import org.outerj.daisy.repository.Repository; 22 import org.outerj.daisy.repository.query.FacetConf; 23 import org.outerj.daisy.repository.query.QueryHelper; 24 import org.outerj.daisy.xmlutil.LocalSAXParserFactory; 25 import org.apache.cocoon.components.flow.apples.StatelessAppleController; 26 import org.apache.cocoon.components.flow.apples.AppleRequest; 27 import org.apache.cocoon.components.flow.apples.AppleResponse; 28 import org.apache.cocoon.environment.Request; 29 import org.apache.avalon.framework.service.Serviceable; 30 import org.apache.avalon.framework.service.ServiceManager; 31 import org.apache.avalon.framework.service.ServiceException; 32 import org.apache.xmlbeans.XmlOptions; 33 import org.apache.xmlbeans.XmlException; 34 import org.apache.xmlbeans.XmlError; 35 import org.outerx.daisy.x10.FacetedQueryResultDocument; 36 import org.outerx.daisy.x10Facetednavdef.FacetedNavigationDefinitionDocument; 37 38 import java.util.*; 39 import java.io.File ; 40 41 public class FacetedBrowserApple extends AbstractDaisyApple implements StatelessAppleController, Serviceable { 42 private ServiceManager serviceManager; 43 44 public void service(ServiceManager serviceManager) throws ServiceException { 45 this.serviceManager = serviceManager; 46 } 47 48 protected void processInternal(AppleRequest appleRequest, AppleResponse appleResponse) throws Exception { 49 Request request = appleRequest.getCocoonRequest(); 50 Locale locale = WikiHelper.getLocale(request); 51 SiteConf siteConf = WikiHelper.getSiteConf(request); 52 Repository repository = WikiHelper.getRepository(request, serviceManager); 53 54 String definitionName = appleRequest.getSitemapParameter("definitionName"); 55 FacetedNavigationDefinition facetedNavDef = loadFacetDefinitions(definitionName, siteConf); 56 FacetDefinition[] facetDefs = facetedNavDef.getFacetDefinitions(); 57 58 Filter[] filters = parseFilters(request, facetedNavDef); 59 Condition[] conditions = filtersToConditions(filters, facetedNavDef); 60 boolean limitToSiteCollection = RequestUtil.getBooleanParameter(request, "limitToSiteCollection", facetedNavDef.getLimitToSiteCollection()); 61 boolean limitToSiteVariant = RequestUtil.getBooleanParameter(request, "limitToSiteVariant", facetedNavDef.getLimitToSiteVariant()); 62 String orderBy = RequestUtil.getStringParameter(request, "orderBy", "name ASC"); 63 64 StringBuffer query = new StringBuffer (); 65 query.append("select "); 66 String [] auxiliaryFields = facetedNavDef.getAuxiliaryFields(); 67 for (int i = 0; i < auxiliaryFields.length; i++) { 68 if (i > 0) 69 query.append(", "); 70 query.append(auxiliaryFields[i]); 71 } 72 for (int i = 0; i < facetDefs.length; i++) { 73 if (i > 0 || auxiliaryFields.length > 0) 74 query.append(", "); 75 query.append(facetDefs[i].getExpression()); 76 } 77 query.append(" where "); 78 if (conditions.length == 0) { 79 query.append("true"); 80 } else { 81 for (int i = 0; i < conditions.length; i++) { 82 if (i > 0) 83 query.append(" and "); 84 query.append(conditions[i].toString()); 85 } 86 } 87 if (limitToSiteCollection) { 88 String collectionName = repository.getCollectionManager().getCollection(siteConf.getCollectionId(), false).getName(); 89 query.append(" and InCollection("); 90 query.append(QueryHelper.formatString(collectionName)); 91 query.append(")"); 92 } 93 if (limitToSiteVariant) { 94 String branchName = repository.getVariantManager().getBranch(siteConf.getBranchId(), false).getName(); 95 String languageName = repository.getVariantManager().getLanguage(siteConf.getLanguageId(), false).getName(); 96 query.append(" and branch = "); 97 query.append(QueryHelper.formatString(branchName)); 98 query.append(" and language = "); 99 query.append(QueryHelper.formatString(languageName)); 100 } 101 if (facetedNavDef.getDefaultConditions() != null) { 102 query.append(" and ( ").append(facetedNavDef.getDefaultConditions()).append(" ) "); 103 } 104 query.append(" order by ").append(orderBy); 105 106 FacetConf[] facetConfs = parseFacetConfs(request, facetedNavDef); 107 108 int chunkOffset = RequestUtil.getIntParameter(request, "chunkOffset", 1); 109 int chunkLength = RequestUtil.getIntParameter(request, "chunkLength", 10); 110 111 FacetedQueryResultDocument result = repository.getQueryManager().performFacetedQuery(query.toString(), facetConfs, chunkOffset, chunkLength, locale); 112 113 HashMap viewData = new HashMap(); 114 viewData.put("facetedQueryResult", new XmlObjectXMLizable(result)); 115 viewData.put("filters", filters); 116 viewData.put("facetedNavDef", facetedNavDef); 117 viewData.put("facetConfs", facetConfs); 118 viewData.put("limitToSiteCollection", String.valueOf(limitToSiteCollection)); 119 viewData.put("limitToSiteVariant", String.valueOf(limitToSiteVariant)); 120 viewData.put("orderBy", orderBy); 121 viewData.put("pageContext", new PageContext(getMountPoint(), siteConf, repository, getLayoutType(), getSkin(), getContext())); 122 viewData.put("path", getMountPoint() + "/" + siteConf.getName() + "/facetedBrowser/" + definitionName); 123 appleResponse.sendPage("FacetedBrowserPipe", viewData); 124 } 125 126 private FacetConf[] parseFacetConfs(Request request, FacetedNavigationDefinition facetedNavDef) throws Exception { 127 FacetDefinition[] facetDefs = facetedNavDef.getFacetDefinitions(); 128 String [] auxiliaryFields = facetedNavDef.getAuxiliaryFields(); 129 FacetConf[] facetConfs = new FacetConf[auxiliaryFields.length + facetDefs.length]; 130 for (int i = 0; i < auxiliaryFields.length; i++) { 131 facetConfs[i] = new FacetConf(false); 132 } 133 134 for (int i = 0; i < facetDefs.length; i++) { 135 String prefix = "facetConf." + (i + 1) + "."; 136 int maxValues = RequestUtil.getIntParameter(request, prefix + "maxValues", 10); 137 boolean sortOnValue = RequestUtil.getBooleanParameter(request, prefix + "sortOnValue", true); 138 boolean sortAscending = RequestUtil.getBooleanParameter(request, prefix + "sortAscending", true); 139 facetConfs[auxiliaryFields.length + i] = new FacetConf(maxValues, sortOnValue, sortAscending); 140 } 141 142 return facetConfs; 143 } 144 145 private Filter[] parseFilters(Request request, FacetedNavigationDefinition facetedNavDef) throws Exception { 146 List filters = new ArrayList(); 147 int i = 1; 148 while (true) { 149 String facetIndex = "filter." + i; 150 String facetName = request.getParameter(facetIndex + ".facetName"); 151 if (facetName == null) 152 break; 153 facetedNavDef.getFacetDefinition(facetName); 154 String queryValue = RequestUtil.getStringParameter(request, facetIndex + ".queryValue"); 155 String displayValue = RequestUtil.getStringParameter(request, facetIndex + ".displayValue"); 156 String operatorKey = RequestUtil.getStringParameter(request, facetIndex + ".operator"); 157 Operator operator = (Operator)operators.get(operatorKey); 158 if (operator == null) 159 throw new Exception ("Non-existing operator: " + operatorKey); 160 161 Filter filter = new Filter(facetName, operator, queryValue, displayValue); 162 filters.add(filter); 163 i++; 164 } 165 return (Filter[])filters.toArray(new Filter[filters.size()]); 166 } 167 168 public static class Filter { 169 private String facetName; 170 private Operator operator; 171 private String queryValue; 172 private String displayValue; 173 174 public Filter(String facetName, Operator operator, String queryValue, String displayValue) { 175 this.facetName = facetName; 176 this.operator = operator; 177 this.queryValue = queryValue; 178 this.displayValue = displayValue; 179 } 180 181 public String getFacetName() { 182 return facetName; 183 } 184 185 public Operator getOperator() { 186 return operator; 187 } 188 189 public String getQueryValue() { 190 return queryValue; 191 } 192 193 public String getDisplayValue() { 194 return displayValue; 195 } 196 } 197 198 private Condition[] filtersToConditions(Filter[] filters, FacetedNavigationDefinition facetedNavDef) { 199 Map conditions = new HashMap(); 200 201 for (int i = 0; i < filters.length; i++) { 202 Condition condition = (Condition)conditions.get(filters[i].getFacetName()); 203 if (condition == null) { 204 FacetDefinition facetDef = facetedNavDef.getFacetDefinition(filters[i].getFacetName()); 205 condition = new Condition(facetDef.getExpression(), Operator.EQUALS, filters[i].getQueryValue()); 206 conditions.put(filters[i].getFacetName(), condition); 207 } else { 208 condition.addValue(filters[i].getQueryValue()); 209 } 210 } 211 212 return (Condition[])conditions.values().toArray(new Condition[conditions.size()]); 213 } 214 215 public static class Condition { 216 private String identifier; 217 private String value; 218 private List values; 219 private Operator operator; 220 221 public Condition(String identifier, Operator operator, String value) { 222 this.identifier = identifier; 223 this.operator = operator; 224 this.value = value; 225 } 226 227 public void addValue(String value) { 228 if (values == null) { 229 values = new ArrayList(); 230 values.add(this.value); 231 this.value = null; 232 } 233 values.add(value); 234 } 235 236 public String toString() { 237 if (values != null) { 238 StringBuffer result = new StringBuffer (); 239 result.append(identifier); 240 result.append(" has all("); 241 for (int i = 0; i < values.size(); i++) { 242 if (i > 0) 243 result.append(", "); 244 result.append(values.get(i)); 245 } 246 result.append(")"); 247 return result.toString(); 248 } else { 249 return identifier + " " + operator.getSyntax() + " " + value; 250 } 251 } 252 } 253 254 private static Map operators = new HashMap(); 255 static { 256 operators.put(Operator.EQUALS.getKey(), Operator.EQUALS); 257 operators.put(Operator.LIKE.getKey(), Operator.LIKE); 258 } 259 260 public static class Operator { 261 private final String key; 262 private final String syntax; 263 264 private Operator(String key, String syntax) { 265 this.key = key; 266 this.syntax = syntax; 267 } 268 269 public String getKey() { 270 return key; 271 } 272 273 public String getSyntax() { 274 return syntax; 275 } 276 277 public String toString() { 278 return key; 279 } 280 281 public static final Operator EQUALS = new Operator("equals", "="); 282 public static final Operator LIKE = new Operator("like", "like"); 283 } 284 285 private FacetedNavigationDefinition loadFacetDefinitions(String name, SiteConf siteConf) throws Exception { 286 File file = new File (new File (siteConf.getDirectory(), "facetednavdefs"), name + ".xml"); 288 if (!file.exists()) 289 throw new Exception ("Faceted navigation definition does not exist: \"" + name + "\""); 290 291 List errors = new ArrayList(); 292 XmlOptions xmlOptions = new XmlOptions(); 293 xmlOptions.setLoadUseXMLReader(LocalSAXParserFactory.newXmlReader()); 294 xmlOptions.setErrorListener(errors); 295 xmlOptions.setLoadLineNumbers(); 296 boolean valid = true; 297 FacetedNavigationDefinitionDocument facetedNavDefDoc; 298 try { 299 facetedNavDefDoc = FacetedNavigationDefinitionDocument.Factory.parse(file, xmlOptions); 300 301 xmlOptions = new XmlOptions(); 302 xmlOptions.setErrorListener(errors); 303 valid = facetedNavDefDoc.validate(xmlOptions); 304 } catch (XmlException e) { 305 throw new Exception ("Error loading faceted navigation definition: " + formatXmlErrors(errors), e); 306 } catch (Exception e) { 307 throw new Exception ("Error loading faceted navigation definition.", e); 308 } 309 310 if (!valid) 311 throw new Exception ("Error validating faceted navigation definition: " + formatXmlErrors(errors)); 312 313 HashSet names = new HashSet(); 314 FacetedNavigationDefinitionDocument.FacetedNavigationDefinition.Facets.Facet[] facetDefsXml = facetedNavDefDoc.getFacetedNavigationDefinition().getFacets().getFacetArray(); 315 FacetDefinition[] facetDefs = new FacetDefinition[facetDefsXml.length]; 316 for (int i = 0; i < facetDefsXml.length; i++) { 317 String expression = facetDefsXml[i].getExpression(); 318 String facetName = makeFacetName(expression); 319 if (names.contains(facetName)) { 320 String baseFacetName = facetName; 321 int s = 1; 322 while (names.contains(facetName)) { 323 facetName = baseFacetName + "-" + s; 324 s++; 325 } 326 } 327 names.add(facetName); 328 facetDefs[i] = new FacetDefinition(facetName, facetDefsXml[i].getExpression()); 329 } 330 331 FacetedNavigationDefinitionDocument.FacetedNavigationDefinition.Options options = facetedNavDefDoc.getFacetedNavigationDefinition().getOptions(); 332 return new FacetedNavigationDefinition(facetDefs, new String [] {"name", "summary"}, 333 options.getLimitToSiteCollection(), options.getLimitToSiteVariant(), options.getDefaultConditions()); 334 } 335 336 private String formatXmlErrors(Collection xmlErrors) { 337 StringBuffer message = new StringBuffer (); 338 Iterator errorsIt = xmlErrors.iterator(); 339 while (errorsIt.hasNext()) { 340 XmlError error = (XmlError)errorsIt.next(); 341 if (message.length() > 0) 342 message.append("\n"); 343 message.append(error.getMessage()); 344 } 345 return message.toString(); 346 } 347 348 private String makeFacetName(String expression) { 349 StringBuffer name = new StringBuffer (expression.length()); 350 for (int i = 0; i < expression.length(); i++) { 351 char c = expression.charAt(i); 352 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) 353 name.append(c); 354 } 355 return name.toString(); 356 } 357 358 public static class FacetedNavigationDefinition { 359 private FacetDefinition[] facetDefinitions; 360 private Map facetsByName = new HashMap(); 361 private String [] auxiliaryFields; 362 private boolean limitToSiteCollection; 363 private boolean limitToSiteVariant; 364 private String defaultConditions; 365 366 public FacetedNavigationDefinition(FacetDefinition[] facetDefinitions, String [] auxiliaryFields, 367 boolean limitToSiteCollection, boolean limitToSiteVariant, String defaultConditions) { 368 this.facetDefinitions = facetDefinitions; 369 for (int i = 0; i < facetDefinitions.length; i++) { 370 if (facetsByName.containsKey(facetDefinitions[i].getName())) 371 throw new RuntimeException ("Duplicate facet name: " + facetDefinitions[i].getName()); 372 facetsByName.put(facetDefinitions[i].getName(), facetDefinitions[i]); 373 } 374 this.auxiliaryFields = auxiliaryFields; 375 this.limitToSiteCollection = limitToSiteCollection; 376 this.limitToSiteVariant = limitToSiteVariant; 377 this.defaultConditions = defaultConditions; 378 } 379 380 public FacetDefinition[] getFacetDefinitions() { 381 return facetDefinitions; 382 } 383 384 public FacetDefinition getFacetDefinition(String name) { 385 FacetDefinition facetDefinition = (FacetDefinition)facetsByName.get(name); 386 if (facetDefinition == null) 387 throw new RuntimeException ("Non-existing facet name: " + name); 388 return facetDefinition; 389 } 390 391 public String [] getAuxiliaryFields() { 392 return auxiliaryFields; 393 } 394 395 public boolean getLimitToSiteCollection() { 396 return limitToSiteCollection; 397 } 398 399 public boolean getLimitToSiteVariant() { 400 return limitToSiteVariant; 401 } 402 403 public String getDefaultConditions() { 404 return defaultConditions; 405 } 406 } 407 408 public static class FacetDefinition { 409 private String name; 410 private String expression; 411 412 public FacetDefinition(String name, String identifier) { 413 this.name = name; 414 this.expression = identifier; 415 } 416 417 public String getName() { 418 return name; 419 } 420 421 public String getExpression() { 422 return expression; 423 } 424 } 425 } 426 | Popular Tags |