1
2
3
4 package org.rcfaces.core.internal.contentStorage;
5
6 import java.io.IOException;
7 import java.io.InputStream;
8 import java.io.Serializable;
9
10 import javax.faces.FacesException;
11 import javax.faces.component.StateHolder;
12 import javax.faces.component.UIComponentBase;
13 import javax.faces.context.FacesContext;
14
15 import org.apache.commons.logging.Log;
16 import org.apache.commons.logging.LogFactory;
17 import org.rcfaces.core.internal.Constants;
18 import org.rcfaces.core.internal.RcfacesContext;
19 import org.rcfaces.core.internal.adapter.IAdapterManager;
20 import org.rcfaces.core.internal.content.ContentAdapterFactory;
21 import org.rcfaces.core.internal.contentAccessor.BasicContentAccessor;
22 import org.rcfaces.core.internal.contentAccessor.BasicGeneratedResourceInformation;
23 import org.rcfaces.core.internal.contentAccessor.BasicGenerationResourceInformation;
24 import org.rcfaces.core.internal.contentAccessor.ContentAccessorFactory;
25 import org.rcfaces.core.internal.contentAccessor.IContentAccessor;
26 import org.rcfaces.core.internal.contentAccessor.IContentPath;
27 import org.rcfaces.core.internal.contentAccessor.IGeneratedResourceInformation;
28 import org.rcfaces.core.internal.contentAccessor.IGenerationResourceInformation;
29 import org.rcfaces.core.internal.lang.LimitedMap;
30 import org.rcfaces.core.internal.lang.StringAppender;
31 import org.rcfaces.core.lang.IAdaptable;
32 import org.rcfaces.core.lang.IContentFamily;
33 import org.rcfaces.core.model.IContentModel;
34 import org.rcfaces.core.provider.AbstractProvider;
35
36
37
38
39
40
41 public class ContentStorageEngineImpl extends AbstractProvider implements
42 IContentStorageEngine {
43 private static final String REVISION = "$Revision: 1.16 $";
44
45 private static final Log LOG = LogFactory
46 .getLog(ContentStorageEngineImpl.class);
47
48 private static final String DISABLE_CACHE_PARAMETER = "org.rcfaces.core.contentStorage.DISABLE_CACHE";
49
50 private final IContentStorageRepository contentStorageRepository = new BasicContentStorageRepository();
51
52 private int contentStorageServletPathType;
53
54 private final Object contentStorageServletURL_LOCK = new Object();
55
56 private volatile String contentStorageServletURL;
57
58 private IAdapterManager adapterManager;
59
60 private boolean disableCache = false;
61
62 private final LimitedMap registredContentsByGenerationInformation = new LimitedMap(
63 Constants.CONTENT_STORAGE_CACHE_SIZE);
64
65 public void startup(FacesContext facesContext) {
66 super.startup(facesContext);
67
68 RcfacesContext rcfacesContext = RcfacesContext
69 .getInstance(facesContext);
70
71 if (rcfacesContext.getContentStorageEngine() == null) {
72 rcfacesContext.setContentStorageEngine(this);
73 }
74
75 disableCache = "true"
76 .equalsIgnoreCase(facesContext.getExternalContext()
77 .getInitParameter(DISABLE_CACHE_PARAMETER));
78 if (disableCache) {
79 LOG.info("Content storage cache is disabled. (Parameter '"
80 + DISABLE_CACHE_PARAMETER + "' is setted to true.)");
81 }
82
83 contentStorageServletPathType = IContentPath.CONTEXT_PATH_TYPE;
84
85 adapterManager = rcfacesContext.getAdapterManager();
86 }
87
88 public IContentStorageRepository getRepository() {
89 return contentStorageRepository;
90 }
91
92 public String getId() {
93 return "ContentStorageEngine";
94 }
95
96 public IContentAccessor registerContentModel(FacesContext facesContext,
97 IContentModel contentModel,
98 IGeneratedResourceInformation generatedInformation,
99 IGenerationResourceInformation generationInformation) {
100
101 boolean modified = false;
102 if (generatedInformation == null) {
103 generatedInformation = new BasicGeneratedResourceInformation();
104 }
105
106 if (generationInformation == null) {
107 generationInformation = new BasicGenerationResourceInformation();
108
109 ((BasicGenerationResourceInformation) generationInformation)
110 .setProcessAtRequest(true);
111 }
112
113 if (contentStorageServletURL == null) {
114 synchronized (contentStorageServletURL_LOCK) {
115
116 if (contentStorageServletURL == null) {
117 contentStorageServletURL = ContentStorageServlet
118 .getContentStorageBaseURI(facesContext
119 .getExternalContext().getApplicationMap());
120
121 if (contentStorageServletURL == null) {
122 LOG
123 .info("Content storage engine is disabled. (No started Content Storage Servlet)");
124
125 return ContentAccessorFactory.UNSUPPORTED_CONTENT_ACCESSOR;
126 }
127 }
128 }
129 }
130
131 if (generatedInformation.getContentFamily() == null) {
132 generatedInformation.setContentFamily(IContentFamily.USER);
133 }
134
135
136 boolean contentEngineMustBeRegistred = true;
137
138 IContentStorageRepository repository = getRepository();
139
140 String contentEngineId = null;
141 if (disableCache == false) {
142 contentEngineId = contentModel.getContentEngineId();
143 if (contentEngineId == null) {
144 Content content = (Content) registredContentsByGenerationInformation
145 .get(generationInformation);
146 if (content != null) {
147 contentEngineId = content.getContentEngineId();
148 contentEngineMustBeRegistred = false;
149
150 if (LOG.isDebugEnabled()) {
151 LOG.debug("Content is already in cache ! information='"
152 + generationInformation + "'");
153 }
154
155 IGeneratedResourceInformation contentGeneratedResourceInformation = content
156 .getGeneratedInformation();
157
158 if (contentGeneratedResourceInformation != null) {
159 contentGeneratedResourceInformation
160 .copyTo(generatedInformation);
161 }
162 } else {
163 if (LOG.isDebugEnabled()) {
164 LOG.debug("Cache does not contain information='"
165 + generationInformation + "'");
166 }
167
168 }
169 }
170 } else {
171 if (LOG.isDebugEnabled()) {
172 LOG.debug("Cache is disabled for information='"
173 + generationInformation + "'");
174 }
175 }
176
177 generatedInformation.setProcessingAtRequest(generationInformation
178 .isProcessAtRequest());
179 contentModel.setInformations(generationInformation,
180 generatedInformation);
181
182 IResolvedContent resolvedContent = null;
183
184 if (contentEngineId != null) {
185 contentModel.setContentEngineId(contentEngineId);
186
187 if (contentModel.checkNotModified()) {
188
189 if (LOG.isDebugEnabled()) {
190 LOG.debug("ContentModel '" + contentModel
191 + "' is not modified !");
192 }
193 resolvedContent = repository.load(contentEngineId);
194
195 if (resolvedContent == null) {
196
197 contentEngineId = null;
198 contentEngineMustBeRegistred = true;
199
200 registredContentsByGenerationInformation
201 .remove(generationInformation);
202 }
203 } else {
204
205
206 contentEngineId = null;
207 contentEngineMustBeRegistred = true;
208
209 registredContentsByGenerationInformation
210 .remove(generationInformation);
211 }
212 }
213
214 if (resolvedContent == null) {
215
216 if (generatedInformation.isProcessingAtRequest()) {
217
218
219 String specifiedSuffix = generationInformation
220 .getResponseSuffix();
221 String specifiedContentType = generationInformation
222 .getResponseMimeType();
223
224 String specifiedResourceKey = null;
225 if (generationInformation
226 .getComputeResourceKeyFromGenerationInformation()) {
227 specifiedResourceKey = BasicGenerationResourceInformation
228 .generateResourceKeyFromGenerationInformation(generationInformation);
229 }
230
231 long specifiedLastModificationDate = generationInformation
232 .getResponseLastModified();
233
234 resolvedContent = new ResolvedContentAtRequest(contentModel,
235 specifiedContentType, specifiedSuffix,
236 specifiedLastModificationDate, specifiedResourceKey,
237 generationInformation);
238
239 } else {
240 Object wrappedData = contentModel.getWrappedData();
241
242
243
244 if (wrappedData instanceof IResolvedContent) {
245 resolvedContent = (IResolvedContent) wrappedData;
246
247 } else {
248
249 AdaptationParameters parametrizedAdaptation = new AdaptationParameters(
250 contentModel, generationInformation,
251 generatedInformation);
252
253 try {
254 if (wrappedData instanceof IAdaptable) {
255 resolvedContent = (IResolvedContent) ((IAdaptable) wrappedData)
256 .getAdapter(IResolvedContent.class,
257 parametrizedAdaptation);
258 }
259
260 if (resolvedContent == null) {
261 resolvedContent = (IResolvedContent) adapterManager
262 .getAdapter(wrappedData,
263 IResolvedContent.class,
264 parametrizedAdaptation);
265 }
266 } catch (Exception ex) {
267 LOG.error(
268 "Can not adapt content while render phase. (information='"
269 + generationInformation + "')", ex);
270 }
271 }
272
273 if (resolvedContent == null) {
274 throw new FacesException("Can not transform raw object '"
275 + contentModel.getClass()
276 + "' to IResolvedContentModel !");
277 }
278
279 try {
280
281
282 resolvedContent.getLength();
283
284 } catch (Exception e) {
285 LOG.error(
286 "Can not resolve content while render phase. (information='"
287 + generationInformation + "')", e);
288
289 return null;
290 }
291 }
292 }
293
294
295 String url = repository.save(resolvedContent, contentModel);
296
297 if (contentEngineMustBeRegistred) {
298 contentEngineId = contentModel.getContentEngineId();
299 if (contentEngineId != null) {
300 registredContentsByGenerationInformation.put(
301 generationInformation, new Content(
302
303 generatedInformation, contentEngineId));
304 }
305 }
306
307 IContentAccessor contentAccessor = new BasicContentAccessor(null,
308 contentStorageServletURL + '/' + url, generatedInformation
309 .getContentFamily());
310
311 contentAccessor.setPathType(contentStorageServletPathType);
312
313 return contentAccessor;
314 }
315
316 public IContentAccessor registerRaw(FacesContext facesContext, Object ref,
317 IGeneratedResourceInformation generatedInformation) {
318
319 if (contentStorageServletURL == null) {
320 LOG
321 .info("ContentStorage is not initialized. (Servlet path is invalid)");
322
323 return ContentAccessorFactory.UNSUPPORTED_CONTENT_ACCESSOR;
324 }
325
326 IResolvedContent resolvedContent = null;
327 if (ref instanceof IAdaptable) {
328 resolvedContent = (IResolvedContent) ((IAdaptable) ref).getAdapter(
329 IResolvedContent.class, null);
330 }
331
332 if (resolvedContent == null) {
333 resolvedContent = (IResolvedContent) adapterManager.getAdapter(ref,
334 IResolvedContent.class, null);
335 }
336
337 if (resolvedContent == null) {
338 throw new FacesException("Can not transform raw object '"
339 + ref.getClass() + "' to IResolvedContent !");
340 }
341
342 String url = getRepository().save(resolvedContent, null);
343
344 if (generatedInformation.getContentFamily() == null) {
345 generatedInformation.setContentFamily(IContentFamily.USER);
346 }
347
348 IContentAccessor contentAccessor = new BasicContentAccessor(
349 facesContext, contentStorageServletURL + '/' + url,
350 generatedInformation.getContentFamily());
351
352 contentAccessor.setPathType(contentStorageServletPathType);
353
354 return contentAccessor;
355 }
356
357
358
359
360
361
362 public static class ResolvedContentAtRequest extends
363 AbstractResolvedContent implements IResolvedContentWrapper,
364 Serializable {
365 private static final String REVISION = "$Revision: 1.16 $";
366
367 private static final long serialVersionUID = -7807317078965658005L;
368
369 private final IContentModel contentModel;
370
371 private transient IResolvedContent resolvedContent;
372
373 private transient boolean errorState;
374
375 private final String specifiedContentType;
376
377 private final String specifiedURLSuffix;
378
379 private final long specifiedLastModificationDate;
380
381 private final String specifiedResourceKey;
382
383 private final IGenerationResourceInformation generationInformation;
384
385 public ResolvedContentAtRequest(IContentModel contentModel,
386 String specifiedContentType, String specifiedURLSuffix,
387 long specifiedLastModificationDate,
388 String specifiedResourceKey,
389 IGenerationResourceInformation generationInformation) {
390 this.contentModel = contentModel;
391
392 if (specifiedURLSuffix == null && specifiedContentType != null) {
393 specifiedURLSuffix = ContentAdapterFactory
394 .getSuffixByMimeType(specifiedContentType);
395 }
396
397 this.specifiedURLSuffix = specifiedURLSuffix;
398 this.specifiedContentType = specifiedContentType;
399 this.specifiedLastModificationDate = specifiedLastModificationDate;
400 this.specifiedResourceKey = specifiedResourceKey;
401 this.generationInformation = generationInformation;
402 }
403
404 public String getContentType() {
405
406 if (isContentResolved()) {
407 return getResolvedContent().getContentType();
408 }
409
410 return specifiedContentType;
411 }
412
413 protected boolean isContentResolved() {
414 if (errorState) {
415 return false;
416 }
417
418 return resolvedContent != null;
419 }
420
421 public String getURLSuffix() {
422 if (isContentResolved()) {
423 return getResolvedContent().getURLSuffix();
424 }
425
426 return specifiedURLSuffix;
427 }
428
429 public InputStream getInputStream() throws IOException {
430 return getResolvedContent().getInputStream();
431 }
432
433 public long getModificationDate() {
434 if (isContentResolved()) {
435 return getResolvedContent().getModificationDate();
436 }
437
438 return specifiedLastModificationDate;
439 }
440
441 public int getLength() {
442 return getResolvedContent().getLength();
443 }
444
445 public void appendHashInformations(StringAppender sa) {
446
447
448 if (specifiedResourceKey != null) {
449
450 return;
451 }
452
453 getResolvedContent().appendHashInformations(sa);
454 }
455
456 public synchronized IResolvedContent getResolvedContent() {
457 if (errorState) {
458 return null;
459 }
460
461 if (resolvedContent != null) {
462 return resolvedContent;
463 }
464
465 try {
466 Object wrappedData = contentModel.getWrappedData();
467
468 AdaptationParameters parametrizedAdaptation = new AdaptationParameters(
469 contentModel, generationInformation, null);
470
471 if (wrappedData instanceof IAdaptable) {
472 resolvedContent = (IResolvedContent) ((IAdaptable) wrappedData)
473 .getAdapter(IResolvedContent.class,
474 parametrizedAdaptation);
475
476 if (resolvedContent != null) {
477 return resolvedContent;
478 }
479 }
480
481 RcfacesContext rcfacesContext = RcfacesContext
482 .getCurrentInstance();
483
484 resolvedContent = (IResolvedContent) rcfacesContext
485 .getAdapterManager().getAdapter(wrappedData,
486 IResolvedContent.class, parametrizedAdaptation);
487
488 if (resolvedContent != null) {
489 return resolvedContent;
490 }
491
492 throw new FacesException(
493 "Can not transform wrappedData of content model '"
494 + wrappedData + "' !");
495
496 } catch (RuntimeException ex) {
497
498 errorState = true;
499
500 throw ex;
501 }
502 }
503
504 public boolean isProcessAtRequest() {
505 return true;
506 }
507
508 public boolean isErrored() {
509 IResolvedContent resolvedContent = getResolvedContent();
510
511 return errorState || resolvedContent.isErrored();
512 }
513
514 public String getETag() {
515 return getResolvedContent().getETag();
516 }
517
518 public String getHash() {
519 return getResolvedContent().getHash();
520 }
521
522 public String getResourceKey() {
523 if (isContentResolved() == false && isProcessAtRequest()) {
524
525
526 if (specifiedResourceKey != null) {
527 return specifiedResourceKey;
528 }
529
530 if (contentModel instanceof IResourceKey) {
531
532 return ((IResourceKey) contentModel).getResourceKey();
533 }
534 return null;
535 }
536
537 return getResolvedContent().getResourceKey();
538 }
539 }
540
541
542
543
544
545
546 public static class Content implements StateHolder {
547 private static final String REVISION = "$Revision: 1.16 $";
548
549
550
551 private IGeneratedResourceInformation generatedInformation;
552
553 private String contentEngineId;
554
555 private boolean transientFlag;
556
557 public Content(
558
559 IGeneratedResourceInformation generatedInformation,
560 String contentEngineId) {
561 this.contentEngineId = contentEngineId;
562
563 this.generatedInformation = generatedInformation;
564 }
565
566 public boolean isTransient() {
567 return transientFlag;
568 }
569
570 public void setTransient(boolean transientFlag) {
571 this.transientFlag = transientFlag;
572 }
573
574 public void restoreState(FacesContext context, Object state) {
575 Object states[] = (Object[]) state;
576
577 contentEngineId = (String) states[0];
578
579
580
581
582 generatedInformation = (IGeneratedResourceInformation) UIComponentBase
583 .restoreAttachedState(context, states[2]);
584 }
585
586 public Object saveState(FacesContext context) {
587 Object states[] = new Object[3];
588
589 states[0] = contentEngineId;
590
591
592
593
594 states[2] = UIComponentBase.saveAttachedState(context,
595 generatedInformation);
596
597 return states;
598 }
599
600 public final IGeneratedResourceInformation getGeneratedInformation() {
601 return generatedInformation;
602 }
603
604 public final String getContentEngineId() {
605 return contentEngineId;
606 }
607 }
608 }