1
2
3
4
5 package org.rcfaces.core.internal.repository;
6
7 import java.io.InputStream;
8 import java.net.MalformedURLException;
9 import java.net.URL;
10 import java.util.ArrayList;
11 import java.util.Arrays;
12 import java.util.Collection;
13 import java.util.HashMap;
14 import java.util.HashSet;
15 import java.util.Iterator;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Set;
19 import java.util.StringTokenizer;
20
21 import javax.servlet.ServletContext;
22
23 import org.apache.commons.digester.Digester;
24 import org.apache.commons.digester.Rule;
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.rcfaces.core.internal.util.ClassLocator;
28 import org.rcfaces.core.internal.util.URLContentProvider;
29 import org.xml.sax.Attributes;
30
31
32
33
34
35 public class BasicHierarchicalRepository extends AbstractRepository
36 implements IHierarchicalRepository {
37
38 private static final String REVISION = "$Revision: 1.1 $";
39
40 private static final long serialVersionUID = -6882051141540673466L;
41
42 private static final Log LOG = LogFactory
43 .getLog(BasicHierarchicalRepository.class);
44
45 protected static final IHierarchicalFile[] HIERARCHICAL_FILE_EMPTY_ARRAY = new IHierarchicalFile[0];
46
47 private static final IModule[] MODULE_EMPTY_ARRAY = new IModule[0];
48
49 private static final Integer FILE_TYPE = new Integer(0);
50
51 private static final Integer MODULE_TYPE = new Integer(1);
52
53 private static final Integer SET_TYPE = new Integer(2);
54
55 private final Map modulesByName = new HashMap();
56
57 private final Map setsByName = new HashMap();
58
59 private final Map resourcesByName = new HashMap();
60
61 private ISet bootSet;
62
63 public BasicHierarchicalRepository(String servletURI,
64 String repositoryVersion) {
65 super(servletURI, repositoryVersion);
66 }
67
68 public ISet getBootSet() {
69 return bootSet;
70 }
71
72 public void setBootSet(ISet set) {
73 this.bootSet = set;
74 }
75
76 protected IContentProvider getDefaultContentProvider() {
77 return URLContentProvider.SINGLETON;
78 }
79
80 public void loadRepository(InputStream input, Object container) {
81
82 Digester digester = new Digester();
83
84 addRules(digester, container);
85
86 try {
87 digester.parse(input);
88
89 } catch (Exception ex) {
90 LOG.error("Can not parse '" + container + "' ", ex);
91 }
92 }
93
94 protected void addRules(Digester digester, final Object container) {
95
96 final String baseDirectory[] = new String[1];
97
98 digester.addRule("repository", new Rule() {
99 private static final String REVISION = "$Revision: 1.1 $";
100
101 public void begin(String namespace, String name,
102 Attributes attributes) throws Exception {
103
104 String contentLocationDirectory = attributes
105 .getValue("baseDirectory");
106
107 if (contentLocationDirectory != null) {
108 if (contentLocationDirectory.length() > 0
109 && contentLocationDirectory.endsWith("/") == false) {
110 contentLocationDirectory += "/";
111 }
112
113 baseDirectory[0] = contentLocationDirectory;
114 }
115
116 }
117 });
118
119 digester.addRule("repository/module", new Rule() {
120 private static final String REVISION = "$Revision: 1.1 $";
121
122 public void begin(String namespace, String name,
123 Attributes attributes) throws Exception {
124 String id = attributes.getValue("id");
125 if (id == null) {
126 throw new IllegalArgumentException(
127 "No 'id' attribute for <module> element !");
128 }
129
130 String filename = getModuleFilename(id);
131 String uri = getURI(filename);
132 boolean groupAllFiles = "true".equalsIgnoreCase(attributes
133 .getValue("groupAll"));
134
135 String rid = "m:" + id;
136
137 IModule m = new Module(rid, filename, uri, groupAllFiles);
138
139 if ("true".equals(attributes.getValue("defaultCoreModule"))) {
140 m.setDefaultCoreModule();
141 }
142
143 filesByURI.put(uri, m);
144 modulesByName.put(id, m);
145 resourcesByName.put(rid, m);
146
147 this.digester.push(m);
148 }
149
150 public void end(String namespace, String name) throws Exception {
151 this.digester.pop();
152 }
153
154 });
155
156 digester.addRule("repository/module/file", new Rule() {
157 private static final String REVISION = "$Revision: 1.1 $";
158
159 public void begin(String namespace, String xname,
160 Attributes attributes) throws Exception {
161
162 String name = attributes.getValue("name");
163 if (name == null) {
164 throw new IllegalArgumentException(
165 "No 'name' attribute for <file> element !");
166 }
167
168 IHierarchicalFile ds[] = HIERARCHICAL_FILE_EMPTY_ARRAY;
169
170 String depends = attributes.getValue("depends");
171 if (depends != null) {
172 List l = null;
173 for (StringTokenizer st = new StringTokenizer(depends, ", "); st
174 .hasMoreTokens();) {
175 String dname = st.nextToken();
176
177 IHierarchicalFile fd = (IHierarchicalFile) getFileByName(dname);
178 if (fd == null) {
179 throw new IllegalArgumentException("Can not find '"
180 + dname + "' referenced by file '" + name
181 + "' !");
182 }
183
184 if (l == null) {
185 l = new ArrayList();
186 }
187
188 l.add(fd);
189 }
190
191 if (l != null) {
192 ds = (IHierarchicalFile[]) l
193 .toArray(new IHierarchicalFile[l.size()]);
194 }
195 }
196
197 IContentProvider contentProvider = null;
198 String contentProviderClassName = attributes
199 .getValue("contentProvider");
200
201 if (contentProviderClassName != null) {
202 try {
203 Class clazz = ClassLocator.load(
204 contentProviderClassName, null, container);
205
206 contentProvider = (IContentProvider) clazz
207 .newInstance();
208
209 } catch (Exception ex) {
210 LOG.error("Can not find contentProvider class '"
211 + contentProviderClassName + "'.", ex);
212
213 throw ex;
214 }
215 }
216
217 IModule module = (IModule) this.digester.peek();
218
219 IHierarchicalFile f = declareFile(name, baseDirectory[0],
220 module, ds, container, contentProvider);
221
222 String uri = getURI(name);
223 filesByURI.put(uri, f);
224
225 this.digester.push(f);
226 }
227
228 public void end(String namespace, String name) throws Exception {
229 this.digester.pop();
230 }
231 });
232 }
233
234 public final IHierarchicalFile declareFile(String name, String directory,
235 IModule module, IHierarchicalFile depends[], Object container,
236 IContentProvider contentProvider) {
237 final String contentLocation = getContentLocation(name, directory);
238
239 URL url = null;
240 if (container instanceof ClassLoader) {
241 String cl = contentLocation;
242 if (cl.startsWith("/")) {
243 cl = cl.substring(1);
244 }
245
246 url = ((ClassLoader) container).getResource(cl);
247
248 if (LOG.isDebugEnabled()) {
249 LOG.debug("Get resource '" + cl + "' from classloader => "
250 + url);
251 }
252 }
253
254 if (url == null && (container instanceof ServletContext)) {
255 String cl = contentLocation;
256 if (cl.startsWith("/") == false) {
257 cl = "/" + cl;
258 }
259
260 try {
261 url = ((ServletContext) container).getResource(cl);
262
263 } catch (MalformedURLException e) {
264 IllegalArgumentException ex = new IllegalArgumentException(
265 "Can not get resource '" + contentLocation
266 + "' into servlet context (file=" + name + ").");
267 ex.initCause(e);
268
269 throw ex;
270 }
271
272 if (LOG.isDebugEnabled()) {
273 LOG.debug("Get resource '" + cl + "' from classloader => "
274 + url);
275 }
276 }
277
278 if (url == null) {
279 throw new IllegalArgumentException("Can not locate file '" + name
280 + "' (location='" + contentLocation + "')");
281 }
282
283 String rname = "f:" + name;
284 IHierarchicalFile f = createFile(module, rname, name, name, url,
285 depends, contentProvider);
286
287 filesByName.put(name, f);
288 resourcesByName.put(rname, f);
289
290 return f;
291 }
292
293 protected HierarchicalFile createFile(IModule module, String name,
294 String filename, String unlocalizedURI,
295 URL unlocalizedContentLocation, IHierarchicalFile dependencies[],
296 IContentProvider contentProvider) {
297
298 return new HierarchicalFile(module, name, filename, unlocalizedURI,
299 unlocalizedContentLocation, dependencies, contentProvider);
300 }
301
302 private String getContentLocation(String name, String directory) {
303 if (directory == null) {
304 return name;
305 }
306 return directory + name;
307 }
308
309 public IModule getModuleByName(String name) {
310 return (IModule) modulesByName.get(name);
311 }
312
313 public IHierarchicalFile getFileById(String id) {
314 return (IHierarchicalFile) resourcesByName.get(id);
315 }
316
317 public ISet getSetByName(String name) {
318 return (ISet) setsByName.get(name);
319 }
320
321 private String getModuleFilename(String id) {
322 return "vfm-" + id + ".js";
323 }
324
325 private String getURI(String name) {
326 return name;
327 }
328
329 public IHierarchicalFile[] computeFiles(Collection files,
330 int typeOfCollection, IContext context) {
331 List dependencies = null;
332 List deps = null;
333
334 for (Iterator it = files.iterator(); it.hasNext();) {
335 Object next = it.next();
336
337 IHierarchicalFile file = convertType(next, typeOfCollection);
338
339 if (file == null) {
340 throw new IllegalArgumentException("Object '" + next
341 + "' can not be converted to file !");
342 }
343
344 if (context.contains(file)) {
345 continue;
346 }
347
348 if (deps == null && dependencies != null) {
349 deps = new ArrayList(dependencies);
350 }
351
352 deps = computeFile(file, context, deps);
353
354 if (deps == null
355 || deps.isEmpty()
356 || (dependencies != null && deps.size() == dependencies
357 .size())) {
358
359 continue;
360 }
361
362
363 if (dependencies == null) {
364 dependencies = new ArrayList(files.size() * 2);
365
366 } else {
367 deps.removeAll(dependencies);
368 }
369
370 dependencies.addAll(deps);
371
372 deps = null;
373 }
374
375 if (dependencies == null || dependencies.isEmpty()) {
376 return HIERARCHICAL_FILE_EMPTY_ARRAY;
377 }
378
379 return (IHierarchicalFile[]) dependencies
380 .toArray(new IHierarchicalFile[dependencies.size()]);
381 }
382
383 protected IHierarchicalFile convertType(Object next, int typeOfCollection) {
384 if (typeOfCollection == FILENAME_COLLECTION_TYPE) {
385 String filename = (String) next;
386
387
388 IHierarchicalFile file = (IHierarchicalFile) filesByName
389 .get(filename);
390 if (file == null) {
391 throw new IllegalArgumentException("File '" + filename
392 + "' is not known into repository !");
393 }
394 return file;
395 }
396
397 if (typeOfCollection == FILE_COLLECTION_TYPE) {
398 return (IHierarchicalFile) next;
399 }
400
401 return null;
402 }
403
404 private List computeFile(IHierarchicalFile file, IContext context,
405 List newFiles) {
406 if (context.contains(file)) {
407 return newFiles;
408 }
409
410 ISet set = null;
411 IModule module = null;
412
413 if (file instanceof ISet) {
414 set = (ISet) file;
415 file = null;
416
417 } else if (file instanceof IModule) {
418 module = (IModule) file;
419 set = module.getSet();
420 file = null;
421
422 } else {
423 module = file.getModule();
424 set = module.getSet();
425 }
426
427 if (module != null && module.getGroupAllFiles()) {
428 if (context.contains(module)) {
429
430 return newFiles;
431 }
432 file = module;
433 }
434
435 if (set != null) {
436 if (context.contains(set)) {
437
438 return newFiles;
439 }
440 file = set;
441 }
442
443 IHierarchicalFile ds[];
444
445 if (file == set) {
446 ds = set.listExternalDependencies();
447
448 } else if (file == module) {
449 ds = module.listExternalDependencies();
450
451 } else {
452 ds = file.listDependencies();
453 }
454
455 if (ds.length > 0) {
456 for (int i = 0; i < ds.length; i++) {
457 newFiles = computeFile(ds[i], context, newFiles);
458 }
459
460 if (set != null && context.contains(set)) {
461 return newFiles;
462 }
463
464
465 if (context.contains(module)) {
466 return newFiles;
467 }
468 }
469
470 if (context.contains(file)) {
471 return newFiles;
472 }
473
474 context.add(file);
475
476 if (newFiles == null) {
477 newFiles = new ArrayList();
478 }
479
480 newFiles.add(file);
481
482 return newFiles;
483 }
484
485 public IModule[] listModules() {
486 Collection c = modulesByName.values();
487
488 return (IModule[]) c.toArray(new IModule[c.size()]);
489 }
490
491 public ISet[] listSets() {
492 Collection c = setsByName.values();
493
494 return (ISet[]) c.toArray(new ISet[c.size()]);
495 }
496
497 public ISet declareSet(String name, String uri, String[] modules) {
498 List l = new ArrayList(modules.length);
499
500 for (int i = 0; i < modules.length; i++) {
501 String moduleName = modules[i];
502
503 IModule module = getModuleByName(moduleName);
504 if (module == null) {
505 throw new IllegalArgumentException(
506 "Can not find module '"
507 + moduleName
508 + "', please check the name or remove it from the web.xml !");
509 }
510
511 addModules(l, module);
512 }
513
514 IModule ms[] = (IModule[]) l.toArray(new IModule[l.size()]);
515
516 return declareSet(name, uri, ms);
517 }
518
519 public ISet declareSet(String name, String uri, IModule[] ms) {
520 for (int i = 0; i < ms.length; i++) {
521 ms[i].setGroupAllFiles(true);
522 }
523
524 String rname = "s:" + name;
525 ISet set = new SetImpl(rname, name, uri, ms);
526
527 filesByURI.put(uri, set);
528 setsByName.put(name, set);
529 resourcesByName.put(rname, set);
530
531 return set;
532 }
533
534 private void addModules(List modules, IModule module) {
535 if (modules.contains(module)) {
536 return;
537 }
538
539 if (module.getSet() != null) {
540 return;
541 }
542
543 IModule extMods[] = module.listExternalModules();
544 if (extMods != null && extMods.length > 0) {
545 for (int i = 0; i < extMods.length; i++) {
546 addModules(modules, extMods[i]);
547 }
548 }
549
550 modules.add(module);
551 }
552
553 private static IModule[] filterModules(IModule[] modules) {
554 List l = new ArrayList(modules.length);
555
556 for (int i = 0; i < modules.length; i++) {
557 IModule module = modules[i];
558
559 if (module.getSet() != null) {
560 continue;
561 }
562
563 l.add(module);
564 }
565
566 return (IModule[]) l.toArray(new IModule[l.size()]);
567 }
568
569
570
571
572
573
574 public class HierarchicalFile extends File implements IHierarchicalFile {
575
576 private static final String REVISION = "$Revision: 1.1 $";
577
578 private static final long serialVersionUID = -4635130019371035269L;
579
580 private final IModule module;
581
582 private final int hashCode;
583
584 private IHierarchicalFile[] dependencies;
585
586 public HierarchicalFile(IModule module, String name, String filename,
587 String unlocalizedURI, Object unlocalizedContentLocation,
588 IHierarchicalFile[] dependencies,
589 IContentProvider contentProvider) {
590 super(name, filename, unlocalizedURI, unlocalizedContentLocation,
591 contentProvider);
592
593 this.module = module;
594 this.dependencies = dependencies;
595
596 if (module != null) {
597 ((Module) module).addFile(this);
598 }
599
600 int h = super.hashCode();
601 if (module != null) {
602
603 h ^= module.getFilename().hashCode();
604 }
605
606 this.hashCode = h;
607 }
608
609 public void addDependencies(IHierarchicalFile dependencies[]) {
610 List l = new ArrayList(Arrays.asList(this.dependencies));
611
612 for (int i = 0; i < dependencies.length; i++) {
613 IHierarchicalFile f = dependencies[i];
614 if (l.contains(f)) {
615 continue;
616 }
617
618 l.add(f);
619 }
620
621 if (LOG.isDebugEnabled()) {
622 LOG.debug("Dependencies of HFile[" + getId() + "]=" + l);
623 }
624
625 this.dependencies = (IHierarchicalFile[]) l
626 .toArray(new IHierarchicalFile[l.size()]);
627 }
628
629 public IHierarchicalFile[] listDependencies() {
630 return dependencies;
631 }
632
633 public IModule getModule() {
634 return module;
635 }
636
637 public int hashCode() {
638 return hashCode;
639 }
640
641 public String toString() {
642 return "[HFile " + getId() + "]";
643 }
644 }
645
646
647
648
649
650
651 public class SetImpl extends HierarchicalFile implements ISet {
652 private static final String REVISION = "$Revision: 1.1 $";
653
654 private static final long serialVersionUID = -5572999892750207302L;
655
656 private IHierarchicalFile externalDependencies[];
657
658 private IHierarchicalFile dependencies[];
659
660 public SetImpl(String id, String filename, String uri,
661 IModule modules[]) {
662 super(null, id, filename, uri, null, filterModules(modules), null);
663
664 modules = (IModule[]) super.listDependencies();
665 for (int i = 0; i < modules.length; i++) {
666 if (modules[i].getSet() != null) {
667 throw new IllegalArgumentException("Module '"
668 + modules[i].getFilename()
669 + "' is already associated to a Set !");
670 }
671
672 ((Module) modules[i]).setSet(this);
673 }
674
675 if (LOG.isDebugEnabled()) {
676 LOG.debug("Declare SET [" + id + "] => "
677 + Arrays.asList(modules));
678 }
679 }
680
681 public IHierarchicalFile[] listExternalDependencies() {
682 if (externalDependencies != null) {
683 return externalDependencies;
684 }
685
686 Set l = null;
687 IHierarchicalFile files[] = listDependencies();
688
689 for (int i = 0; i < files.length; i++) {
690 IHierarchicalFile file = files[i];
691
692 IHierarchicalFile dfiles[] = file.listDependencies();
693
694 for (int j = 0; j < dfiles.length; j++) {
695 IHierarchicalFile dfile = dfiles[j];
696
697 IModule module = dfile.getModule();
698
699 if (module.getSet() == this) {
700 continue;
701 }
702
703 if (l == null) {
704 l = new HashSet();
705 }
706
707 l.add(dfile);
708 }
709 }
710
711 if (LOG.isDebugEnabled()) {
712 LOG.debug("ExternalDependencies of SET[" + getId() + "]=" + l);
713 }
714
715 if (l == null) {
716 externalDependencies = HIERARCHICAL_FILE_EMPTY_ARRAY;
717
718 return externalDependencies;
719 }
720
721 externalDependencies = (IHierarchicalFile[]) l
722 .toArray(new IHierarchicalFile[l.size()]);
723
724 return externalDependencies;
725 }
726
727 public IHierarchicalFile[] listDependencies() {
728 if (dependencies != null) {
729 return dependencies;
730 }
731
732 List l = new ArrayList();
733 IModule modules[] = (IModule[]) super.listDependencies();
734 for (int i = 0; i < modules.length; i++) {
735
736 IHierarchicalFile fs[] = modules[i].listDependencies();
737
738 l.addAll(Arrays.asList(fs));
739 }
740
741 if (LOG.isDebugEnabled()) {
742 LOG.debug("Dependencies of SET[" + getId() + "]=" + l);
743 }
744
745 dependencies = (IHierarchicalFile[]) l
746 .toArray(new IHierarchicalFile[l.size()]);
747
748 return dependencies;
749 }
750
751 public String toString() {
752 return "[Set " + getId() + "]";
753 }
754
755 }
756
757
758
759
760
761
762 public class Module extends HierarchicalFile implements IModule {
763 private static final String REVISION = "$Revision: 1.1 $";
764
765 private static final long serialVersionUID = -5299468486306880225L;
766
767 private boolean groupAllFiles;
768
769 private List filesList = new ArrayList(8);
770
771 private IHierarchicalFile files[];
772
773 private ISet set;
774
775 private IHierarchicalFile externalDependencies[];
776
777 private IModule externalModules[];
778
779 private boolean isDefaultCoreModule;
780
781 public Module(String name, String filename, String uri,
782 boolean groupAllFiles) {
783 super(null, name, filename, uri, null, null, null);
784
785 this.groupAllFiles = groupAllFiles;
786 }
787
788 public boolean isDefaultCoreModule() {
789 return isDefaultCoreModule;
790 }
791
792 public void setDefaultCoreModule() {
793 isDefaultCoreModule = true;
794 }
795
796 public void setGroupAllFiles(boolean enable) {
797 this.groupAllFiles = enable;
798 }
799
800 public boolean getGroupAllFiles() {
801 return groupAllFiles;
802 }
803
804 public void addFile(IHierarchicalFile file) {
805 filesList.add(file);
806 }
807
808 public IHierarchicalFile[] listDependencies() {
809 if (files != null) {
810 return files;
811 }
812
813 files = (IHierarchicalFile[]) filesList
814 .toArray(new IHierarchicalFile[filesList.size()]);
815 filesList = null;
816
817 return files;
818 }
819
820 public IHierarchicalFile[] listExternalDependencies() {
821 if (externalDependencies != null) {
822 return externalDependencies;
823 }
824
825 Set l = null;
826 IHierarchicalFile files[] = listDependencies();
827
828 for (int i = 0; i < files.length; i++) {
829 IHierarchicalFile file = files[i];
830
831 IHierarchicalFile dfiles[] = file.listDependencies();
832
833 for (int j = 0; j < dfiles.length; j++) {
834 IHierarchicalFile dfile = dfiles[j];
835
836 if (dfile.getModule() == this) {
837 continue;
838 }
839
840 if (l == null) {
841 l = new HashSet();
842 }
843
844 l.add(dfile);
845 }
846 }
847
848 if (LOG.isDebugEnabled()) {
849 LOG.debug("ExternalDependencies of MODULE[" + getId() + "]="
850 + l);
851 }
852
853 if (l == null) {
854 externalDependencies = HIERARCHICAL_FILE_EMPTY_ARRAY;
855
856 return externalDependencies;
857 }
858
859 externalDependencies = (IHierarchicalFile[]) l
860 .toArray(new IHierarchicalFile[l.size()]);
861
862 return externalDependencies;
863 }
864
865 public IModule[] listExternalModules() {
866 if (externalModules != null) {
867 return externalModules;
868 }
869
870 Set l = null;
871 IHierarchicalFile files[] = listExternalDependencies();
872
873 for (int i = 0; i < files.length; i++) {
874 IModule module = files[i].getModule();
875 if (module == null) {
876 continue;
877 }
878
879 if (l == null) {
880 l = new HashSet();
881 }
882
883 l.add(module);
884 }
885
886 if (LOG.isDebugEnabled()) {
887 LOG.debug("Dependencies of MODULE[" + getId() + "]=" + l);
888 }
889
890 if (l == null) {
891 externalModules = MODULE_EMPTY_ARRAY;
892
893 return externalModules;
894 }
895
896 externalModules = (IModule[]) l.toArray(new IModule[l.size()]);
897
898 return externalModules;
899 }
900
901 public void setSet(ISet set) {
902 this.set = set;
903 }
904
905 public ISet getSet() {
906 return set;
907 }
908
909 public String toString() {
910 return "[Module " + getId() + "]";
911 }
912 }
913 }