1 16 package org.apache.cocoon.components.source.impl; 17 18 import java.io.ByteArrayInputStream ; 19 import java.io.ByteArrayOutputStream ; 20 import java.io.IOException ; 21 import java.io.InputStream ; 22 import java.io.Serializable ; 23 import java.net.MalformedURLException ; 24 import java.util.Iterator ; 25 import java.util.Map ; 26 27 import org.apache.avalon.framework.component.ComponentManager; 28 import org.apache.avalon.framework.logger.AbstractLogEnabled; 29 import org.apache.avalon.framework.logger.Logger; 30 import org.apache.cocoon.Constants; 31 import org.apache.cocoon.Processor; 32 import org.apache.cocoon.ResourceNotFoundException; 33 import org.apache.cocoon.components.CocoonComponentManager; 34 import org.apache.cocoon.components.pipeline.ProcessingPipeline; 35 import org.apache.cocoon.components.source.SourceUtil; 36 import org.apache.cocoon.environment.Environment; 37 import org.apache.cocoon.environment.ObjectModelHelper; 38 import org.apache.cocoon.environment.wrapper.EnvironmentWrapper; 39 import org.apache.cocoon.environment.wrapper.MutableEnvironmentFacade; 40 import org.apache.cocoon.xml.ContentHandlerWrapper; 41 import org.apache.cocoon.xml.XMLConsumer; 42 import org.apache.excalibur.source.Source; 43 import org.apache.excalibur.source.SourceException; 44 import org.apache.excalibur.source.SourceNotFoundException; 45 import org.apache.excalibur.source.SourceResolver; 46 import org.apache.excalibur.source.SourceValidity; 47 import org.apache.excalibur.xml.sax.XMLizable; 48 import org.xml.sax.ContentHandler ; 49 import org.xml.sax.SAXException ; 50 import org.xml.sax.ext.LexicalHandler ; 51 52 59 public final class SitemapSource 60 extends AbstractLogEnabled 61 implements Source, XMLizable { 62 63 64 private SitemapSourceValidity validity; 65 66 67 private final String systemId; 68 69 70 private String systemIdForCaching; 71 72 73 private final ComponentManager manager; 74 75 76 private final Processor processor; 77 78 79 private Processor pipelineProcessor; 80 81 82 private final MutableEnvironmentFacade environment; 83 84 85 private ProcessingPipeline processingPipeline; 86 87 88 private Source redirectSource; 89 90 91 private SAXException exception; 92 93 94 private boolean needsRefresh; 95 96 97 private Object processKey; 98 99 100 private final String protocol; 101 102 103 private SourceResolver sourceResolver; 104 105 private String mimeType; 106 107 110 public SitemapSource(ComponentManager manager, 111 String uri, 112 Map parameters, 113 Logger logger) 114 throws MalformedURLException { 115 116 Environment env = CocoonComponentManager.getCurrentEnvironment(); 117 if ( env == null ) { 118 throw new MalformedURLException ("The cocoon protocol can not be used outside an environment."); 119 } 120 121 this.manager = manager; 122 this.enableLogging(logger); 123 124 boolean rawMode = false; 125 126 int position = uri.indexOf(':') + 1; 128 if (position != 0) { 129 this.protocol = uri.substring(0, position-1); 130 if (uri.startsWith("raw:", position)) { 132 position += 4; 133 rawMode = true; 134 } 135 } else { 136 throw new MalformedURLException ("No protocol found for sitemap source in " + uri); 137 } 138 139 String prefix; 141 if (uri.startsWith("//", position)) { 142 position += 2; 143 this.processor = CocoonComponentManager.getActiveProcessor(env).getRootProcessor(); 144 prefix = ""; } else if (uri.startsWith("/", position)) { 146 position ++; 147 prefix = null; 148 this.processor = CocoonComponentManager.getActiveProcessor(env); 149 } else { 150 throw new MalformedURLException ("Malformed cocoon URI: " + uri); 151 } 152 153 String queryString = null; 155 int queryStringPos = uri.indexOf('?', position); 156 if (queryStringPos != -1) { 157 queryString = uri.substring(queryStringPos + 1); 158 uri = uri.substring(position, queryStringPos); 159 } else if (position > 0) { 160 uri = uri.substring(position); 161 } 162 163 String view = null; 165 if (queryString != null) { 166 int index = queryString.indexOf(Constants.VIEW_PARAM); 167 if (index != -1 168 && (index == 0 || queryString.charAt(index-1) == '&') 169 && queryString.length() > index + Constants.VIEW_PARAM.length() 170 && queryString.charAt(index+Constants.VIEW_PARAM.length()) == '=') { 171 172 String tmp = queryString.substring(index+Constants.VIEW_PARAM.length()+1); 173 index = tmp.indexOf('&'); 174 if (index != -1) { 175 view = tmp.substring(0,index); 176 } else { 177 view = tmp; 178 } 179 } else { 180 view = env.getView(); 181 } 182 } else { 183 view = env.getView(); 184 } 185 186 String requestURI = (prefix == null ? env.getURIPrefix() + uri : uri); 188 189 this.systemId = queryString == null ? 191 this.protocol + "://" + requestURI : 192 this.protocol + "://" + requestURI + "?" + queryString; 193 194 EnvironmentWrapper wrapper = new EnvironmentWrapper(env, requestURI, 196 queryString, logger, manager, rawMode, view); 197 wrapper.setURI(prefix, uri); 198 199 this.environment = new MutableEnvironmentFacade(wrapper); 201 202 if ( null != parameters ) { 204 this.environment.getObjectModel().put(ObjectModelHelper.PARENT_CONTEXT, parameters); 205 } else { 206 this.environment.getObjectModel().remove(ObjectModelHelper.PARENT_CONTEXT); 207 } 208 209 this.validity = new SitemapSourceValidity(); 211 212 this.init(); 214 } 215 216 219 public String getScheme() { 220 return this.protocol; 221 } 222 223 227 public long getContentLength() { 228 return -1; 229 } 230 231 236 public long getLastModified() { 237 return 0; 238 } 239 240 243 public InputStream getInputStream() 244 throws IOException , SourceException { 245 246 if (this.needsRefresh) { 247 this.refresh(); 248 } 249 if (this.exception != null) { 251 throw new SourceException("Cannot get input stream for " + getURI(), this.exception); 252 } 253 254 if (this.redirectSource != null) { 255 return this.redirectSource.getInputStream(); 256 } 257 258 try { 259 ByteArrayOutputStream os = new ByteArrayOutputStream (); 260 this.environment.setOutputStream(os); 261 CocoonComponentManager.enterEnvironment(this.environment, 262 this.manager, 263 this.pipelineProcessor); 264 try { 265 this.processingPipeline.process(this.environment); 266 } finally { 267 CocoonComponentManager.leaveEnvironment(); 268 } 269 270 return new ByteArrayInputStream (os.toByteArray()); 271 272 } catch (ResourceNotFoundException e) { 273 throw new SourceNotFoundException("Exception during processing of " + this.systemId, e); 274 } catch (Exception e) { 275 throw new SourceException("Exception during processing of " + this.systemId, e); 276 } finally { 277 this.environment.setOutputStream(null); 279 this.needsRefresh = true; 280 } 281 } 282 283 286 public String getURI() { 287 return this.systemIdForCaching; 288 } 289 290 294 public boolean exists() { 295 return true; 296 } 297 298 302 public SourceValidity getValidity() { 303 return this.validity.getNestedValidity() == null? null: this.validity; 304 } 305 306 311 public String getMimeType() { 312 return this.mimeType; 313 } 314 315 319 public void refresh() { 320 this.reset(); 321 this.init(); 322 } 323 324 327 protected void init() { 328 this.systemIdForCaching = this.systemId; 329 try { 330 this.processKey = CocoonComponentManager.startProcessing(this.environment); 331 this.processingPipeline = this.processor.buildPipeline(this.environment); 332 this.pipelineProcessor = CocoonComponentManager.getActiveProcessor(this.environment); 333 334 String redirectURL = this.environment.getRedirectURL(); 335 if (redirectURL == null) { 336 337 CocoonComponentManager.enterEnvironment(this.environment, 338 this.manager, 339 this.pipelineProcessor); 340 try { 341 this.processingPipeline.prepareInternal(this.environment); 342 this.validity.set(this.processingPipeline.getValidityForEventPipeline()); 343 this.mimeType = this.environment.getContentType(); 344 345 final String eventPipelineKey = this.processingPipeline.getKeyForEventPipeline(); 346 if (eventPipelineKey != null) { 347 StringBuffer buffer = new StringBuffer (this.systemId); 348 if (this.systemId.indexOf('?') == -1) { 349 buffer.append('?'); 350 } else { 351 buffer.append('&'); 352 } 353 buffer.append("pipelinehash="); 354 buffer.append(eventPipelineKey); 355 this.systemIdForCaching = buffer.toString(); 356 } else { 357 this.systemIdForCaching = this.systemId; 358 } 359 } finally { 360 CocoonComponentManager.leaveEnvironment(); 361 } 362 } else { 363 if (redirectURL.indexOf(":") == -1) { 364 redirectURL = this.protocol + ":/" + redirectURL; 365 } 366 if (this.sourceResolver == null) { 367 this.sourceResolver = (SourceResolver) this.manager.lookup(SourceResolver.ROLE); 368 } 369 this.redirectSource = this.sourceResolver.resolveURI(redirectURL); 370 this.validity.set(this.redirectSource.getValidity()); 371 this.mimeType = this.redirectSource.getMimeType(); 372 } 373 } catch (SAXException e) { 374 reset(); 375 this.exception = e; 376 } catch (Exception e) { 377 reset(); 378 this.exception = new SAXException ("Could not get sitemap source " + this.systemId, e); 379 } 380 this.needsRefresh = false; 381 } 382 383 386 public void toSAX(ContentHandler contentHandler) 387 throws SAXException { 388 if (this.needsRefresh) { 389 this.refresh(); 390 } 391 if (this.exception != null) { 392 throw this.exception; 393 } 394 try { 395 if (this.redirectSource != null) { 396 SourceUtil.parse(this.manager, this.redirectSource, contentHandler); 397 } else { 398 XMLConsumer consumer; 399 if (contentHandler instanceof XMLConsumer) { 400 consumer = (XMLConsumer)contentHandler; 401 } else if (contentHandler instanceof LexicalHandler ) { 402 consumer = new ContentHandlerWrapper(contentHandler, (LexicalHandler )contentHandler); 403 } else { 404 consumer = new ContentHandlerWrapper(contentHandler); 405 } 406 CocoonComponentManager.enterEnvironment(this.environment, 409 this.manager, 410 this.pipelineProcessor); 411 try { 412 this.processingPipeline.process(this.environment, 413 CocoonComponentManager.createEnvironmentAwareConsumer(consumer)); 414 } finally { 415 CocoonComponentManager.leaveEnvironment(); 416 } 417 } 418 } catch (SAXException e) { 419 throw e; 421 } catch (Exception e) { 422 throw new SAXException ("Exception during processing of " + this.systemId, e); 423 } finally { 424 this.needsRefresh = true; 425 } 426 } 427 428 431 private void reset() { 432 if (this.processingPipeline != null) { 433 this.processingPipeline.release(); 434 this.processingPipeline = null; 435 } 436 437 if (this.processKey != null) { 438 CocoonComponentManager.endProcessing(this.environment, this.processKey); 439 this.processKey = null; 440 } 441 442 if (this.redirectSource != null) { 443 this.sourceResolver.release(this.redirectSource); 444 this.redirectSource = null; 445 } 446 447 this.validity.set(null); 448 449 this.environment.reset(); 450 this.exception = null; 451 this.needsRefresh = true; 452 this.pipelineProcessor = null; 453 } 454 455 458 public void recycle() { 459 this.validity = new SitemapSourceValidity(); 460 this.reset(); 461 if (this.sourceResolver != null) { 462 this.manager.release(this.sourceResolver); 463 this.sourceResolver = null; 464 } 465 } 466 467 472 public String getParameter(String name) { 473 return null; 474 } 475 476 481 public long getParameterAsLong(String name) { 482 return 0; 483 } 484 485 490 public Iterator getParameterNames() { 491 return java.util.Collections.EMPTY_LIST.iterator(); 492 } 493 494 497 public static final class SitemapSourceValidity implements SourceValidity, Serializable { 498 499 private SourceValidity validity; 500 501 private SitemapSourceValidity() { 502 super(); 503 } 504 505 void set(SourceValidity validity) { 506 this.validity = validity; 507 } 508 509 public int isValid() { 510 return (this.validity != null ? 511 this.validity.isValid() : 512 SourceValidity.INVALID); 513 } 514 515 public int isValid(SourceValidity validity) { 516 if (validity instanceof SitemapSourceValidity) { 517 return (this.validity != null ? 518 this.validity.isValid(((SitemapSourceValidity) validity).getNestedValidity()) : 519 SourceValidity.INVALID); 520 } 521 return SourceValidity.INVALID; 522 } 523 524 public SourceValidity getNestedValidity() { 525 return this.validity; 526 } 527 } 528 } 529 | Popular Tags |