KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > filesystems > Repository


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.openide.filesystems;
21
22 import java.beans.PropertyChangeEvent JavaDoc;
23 import java.beans.PropertyChangeListener JavaDoc;
24 import java.beans.PropertyVetoException JavaDoc;
25 import java.beans.VetoableChangeListener JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.io.ObjectInput JavaDoc;
28 import java.io.ObjectInputStream JavaDoc;
29 import java.io.ObjectOutput JavaDoc;
30 import java.io.ObjectOutputStream JavaDoc;
31 import java.io.Serializable JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.Enumeration JavaDoc;
34 import java.util.HashSet JavaDoc;
35 import java.util.Hashtable JavaDoc;
36 import java.util.Iterator JavaDoc;
37 import java.util.Vector JavaDoc;
38 import org.openide.util.io.NbMarshalledObject;
39
40 /**
41  * Holder for system filesystem, used for most of NetBeans' runtime configuration.
42  * There is only one useful thing to do with this class:
43  * <pre>
44  * FileSystem sfs = Repository.getDefault().getDefaultFileSystem();
45  * // now use somehow, e.g.
46  * FileObject menus = sfs.findResource("Menu");
47  * // ...
48  * </pre>
49  * Formerly (NB 3.x) contained a list of mounted filesystems. This functionality
50  * is no longer used and is now deprecated.
51  */

52 public class Repository implements Serializable JavaDoc {
53     static final long serialVersionUID = -6344768369160069704L;
54
55     /** list of filesystems (FileSystem) */
56     private ArrayList JavaDoc<FileSystem> fileSystems;
57     private transient ArrayList JavaDoc<FileSystem> fileSystemsClone;
58
59     /** the system filesystem */
60     private FileSystem system;
61
62     /** hashtable that maps system names to FileSystems */
63     private Hashtable JavaDoc<String JavaDoc, FileSystem> names;
64     private transient FCLSupport fclSupport;
65
66     // [PENDING] access to this hashtable is apparently not propertly synched
67
// should use e.g. Collections.synchronizedSet, or just synch methods using it
68

69     /** hashtable for listeners on changes in the filesystem.
70     * Its elements are of type (RepositoryListener, RepositoryListener)
71     */

72     private Hashtable JavaDoc<RepositoryListener,RepositoryListener> listeners =
73             new Hashtable JavaDoc<RepositoryListener,RepositoryListener>();
74
75     /** vetoable listener on systemName property of filesystem */
76     private VetoableChangeListener JavaDoc vetoListener = new VetoableChangeListener JavaDoc() {
77             /** @param ev event with changes */
78             public void vetoableChange(PropertyChangeEvent JavaDoc ev)
79             throws PropertyVetoException JavaDoc {
80                 if (ev.getPropertyName().equals("systemName")) {
81                     final String JavaDoc ov = (String JavaDoc) ev.getOldValue();
82                     final String JavaDoc nv = (String JavaDoc) ev.getNewValue();
83
84                     if (names.get(nv) != null) {
85                         throw new PropertyVetoException JavaDoc("system name already exists: " + ov + " -> " + nv, ev); // NOI18N
86
}
87                 }
88             }
89         };
90
91     /** property listener on systemName property of filesystem */
92     private PropertyChangeListener JavaDoc propListener = new PropertyChangeListener JavaDoc() {
93             /** @param ev event with changes */
94             public void propertyChange(PropertyChangeEvent JavaDoc ev) {
95                 if (ev.getPropertyName().equals("systemName")) {
96                     // assign the property to new name
97
String JavaDoc ov = (String JavaDoc) ev.getOldValue();
98                     String JavaDoc nv = (String JavaDoc) ev.getNewValue();
99                     FileSystem fs = (FileSystem) ev.getSource();
100
101                     if (fs.isValid()) {
102                         // when a filesystem is valid then it is attached to a name
103
names.remove(ov);
104                     }
105
106                     // register name of the filesystem
107
names.put(nv, fs);
108
109                     // the filesystem becomes valid
110
fs.setValid(true);
111                 }
112             }
113         };
114
115     /** Creates new instance of filesystem pool and
116     * registers it as the default one. Also registers the default filesystem.
117     *
118     * @param def the default filesystem
119     */

120     public Repository(FileSystem def) {
121         this.system = def;
122         init();
123     }
124
125     /** Access method to get default instance of repository in the system.
126      * The instance is either taken as a result of
127      * <CODE>org.openide.util.Lookup.getDefault ().lookup (Repository.class)</CODE>
128      * or (if the lookup query returns null) a default instance is created.
129      *
130      * @return default repository for the system
131      */

132     public static Repository getDefault() {
133         return ExternalUtil.getRepository();
134     }
135
136     /** Initialazes the pool.
137     */

138     private void init() {
139         // empties the pool
140
fileSystems = new ArrayList JavaDoc<FileSystem>();
141         names = new Hashtable JavaDoc<String JavaDoc, FileSystem>();
142         addFileSystem(system);
143     }
144
145     /**
146      * Gets the NetBeans default (system, configuration) filesystem.
147      * @return the default filesystem
148      */

149     public final FileSystem getDefaultFileSystem() {
150         return system;
151     }
152
153     /** Adds new filesystem to the pool.
154     * <em>Note</em> that a filesystem cannot be assigned to more than one file
155     * system pool at one time (though currently there is only one pool anyway).
156     * At any given time, no two filesystems in the pool may share the same {@link FileSystem#getSystemName name}
157     * (unless all but one are {@link FileSystem#isValid invalid}). To be sure, that
158     * filesystem was really added in Repository, then test that <code>FileSystem</code>
159     * is valid.
160     * @param fs filesystem to add
161     * @deprecated Please use the <a HREF="@org-netbeans-api-java@/org/netbeans/api/java/classpath/ClassPath.html">ClassPath API</a> instead.
162     */

163     @Deprecated JavaDoc
164     public final void addFileSystem(FileSystem fs) {
165
166         boolean fireIt = false;
167
168         synchronized (this) {
169             // if the filesystem is not assigned yet
170
if (!fs.assigned && !fileSystems.contains(fs)) {
171                 // new filesystem
172
fs.setRepository(this);
173                 fileSystems.add(fs);
174                 fileSystemsClone = new ArrayList JavaDoc<FileSystem>(fileSystems);
175
176                 String JavaDoc systemName = fs.getSystemName();
177
178                 boolean isReg = names.get(systemName) == null;
179
180                 if (isReg && !systemName.equals("")) { // NOI18N
181

182                     // filesystem with the same name is not there => then it is valid
183
names.put(systemName, fs);
184                     fs.setValid(true);
185                 } else {
186                     // there is another filesystem with the same name => it is invalid
187
fs.setValid(false);
188                 }
189
190                 // mark the filesystem as being assigned
191
fs.assigned = true;
192
193                 // mark as a listener on changes in the filesystem
194
fs.addPropertyChangeListener(propListener);
195                 fs.addVetoableChangeListener(vetoListener);
196
197                 // notify filesystem itself that it has been added
198
fs.addNotify();
199
200                 // fire info about new filesystem
201
fireIt = true;
202             }
203         }
204
205         // postponed firing after synchronized block to prevent deadlock
206
if (fireIt) {
207             fireFileSystem(fs, true);
208         }
209     }
210
211     /** Removes a filesystem from the pool.
212     * @param fs filesystem to remove
213     * @deprecated Please use the <a HREF="@org-netbeans-api-java@/org/netbeans/api/java/classpath/ClassPath.html">ClassPath API</a> instead.
214     */

215     @Deprecated JavaDoc
216     public final void removeFileSystem(FileSystem fs) {
217         boolean fireIt = false;
218
219         synchronized (this) {
220             if (fs.isDefault()) {
221                 return;
222             }
223
224             if (fireIt = fileSystems.remove(fs)) {
225                 fs.setRepository(null);
226                 fileSystemsClone = new ArrayList JavaDoc<FileSystem>(fileSystems);
227
228                 // the filesystem realy was here
229
if (fs.isValid()) {
230                     // if the filesystem is valid then is in names hashtable
231
names.remove(fs.getSystemName());
232                     fs.setValid(false);
233                 }
234
235                 // in all cases remove it from listeners
236
fs.removePropertyChangeListener(propListener);
237                 fs.removeVetoableChangeListener(vetoListener);
238
239                 // notify filesystem itself that it has been removed
240
fs.removeNotify();
241             }
242
243             // unassign the filesystem
244
fs.assigned = false;
245         }
246
247         // postponed firing after synchronized block to prevent deadlock
248
if (fireIt) {
249             fireFileSystem(fs, false);
250         }
251     }
252
253     /** Reorders {@link FileSystem}s by given permutation.
254      * For example, if there are three filesystems, <code>new int[] {2, 0, 1}</code> cycles the filesystems forwards.
255     * @param perm an array of integers
256     * @throws IllegalArgumentException if the array is not a permutation, or is not the same length as the current number of filesystems in the pool
257     * @deprecated Please use the <a HREF="@org-netbeans-api-java@/org/netbeans/api/java/classpath/ClassPath.html">ClassPath API</a> instead.
258     */

259     @Deprecated JavaDoc
260     public final void reorder(int[] perm) {
261         synchronized (this) {
262             if (perm == null) {
263                 throw new IllegalArgumentException JavaDoc("null permutation"); // NOI18N
264
} else if (perm.length != fileSystems.size()) {
265                 throw new IllegalArgumentException JavaDoc(
266                     "permutation is wrong size: " + perm.length + " elements but should be " + fileSystems.size()
267                 ); // NOI18N
268
} else if (!isPermutation(perm)) {
269                 StringBuffer JavaDoc message = new StringBuffer JavaDoc("permutation is not really a permutation:"); // NOI18N
270

271                 for (int i = 0; i < perm.length; i++) {
272                     message.append(' ');
273                     message.append(perm[i]);
274                 }
275
276                 throw new IllegalArgumentException JavaDoc(message.toString());
277             }
278
279             ArrayList JavaDoc<FileSystem> newList = new ArrayList JavaDoc<FileSystem>(fileSystems.size());
280             int len = perm.length;
281
282             for (int i = 0; i < len; i++) {
283                 newList.add(fileSystems.get(perm[i]));
284             }
285
286             fileSystems = newList;
287             fileSystemsClone = new ArrayList JavaDoc<FileSystem>(fileSystems);
288         }
289
290         fireFileSystemReordered(perm);
291     }
292
293     /** @return true if the parameter describes a permutation */
294     private static boolean isPermutation(int[] perm) {
295         final int len = perm.length;
296         boolean[] bool = new boolean[len];
297
298         try {
299             for (int i = 0; i < len; i++) {
300                 if (bool[perm[i]]) {
301                     return false;
302                 } else {
303                     bool[perm[i]] = true;
304                 }
305             }
306
307             return true;
308         } catch (IndexOutOfBoundsException JavaDoc e) {
309             return false;
310         }
311     }
312
313     /** Returns enumeration of all filesystems.
314     * @return enumeration of type {@link FileSystem}
315     * @deprecated Please use the <a HREF="@org-netbeans-api-java@/org/netbeans/api/java/classpath/ClassPath.html">ClassPath API</a> instead.
316     */

317     @Deprecated JavaDoc
318     public final Enumeration JavaDoc<? extends FileSystem> getFileSystems() {
319         ArrayList JavaDoc<FileSystem> tempFileSystems = fileSystemsClone;
320
321         return java.util.Collections.enumeration(tempFileSystems);
322     }
323
324     /** Returns enumeration of all filesystems.
325     * @return enumeration of type {@link FileSystem}
326     * @deprecated Please use the <a HREF="@org-netbeans-api-java@/org/netbeans/api/java/classpath/ClassPath.html">ClassPath API</a> instead.
327     */

328     @Deprecated JavaDoc
329     public final Enumeration JavaDoc<? extends FileSystem> fileSystems() {
330         return getFileSystems();
331     }
332
333     /**
334      * Returns a sorted array of filesystems.
335      * @return a sorted array of filesystems
336      * @deprecated Please use the <a HREF="@org-netbeans-api-java@/org/netbeans/api/java/classpath/ClassPath.html">ClassPath API</a> instead.
337      */

338     @Deprecated JavaDoc
339     public final FileSystem[] toArray() {
340         ArrayList JavaDoc<FileSystem> tempFileSystems = fileSystemsClone;
341
342         FileSystem[] fss = new FileSystem[tempFileSystems.size()];
343         tempFileSystems.toArray(fss);
344
345         return fss;
346     }
347
348     /** Finds filesystem when only its system name is known.
349     * @param systemName {@link FileSystem#getSystemName name} of the filesystem
350     * @return the filesystem or <CODE>null</CODE> if there is no such
351     * filesystem
352     * @deprecated Please use the <a HREF="@org-netbeans-api-java@/org/netbeans/api/java/classpath/ClassPath.html">ClassPath API</a> instead.
353     */

354     @Deprecated JavaDoc
355     public final FileSystem findFileSystem(String JavaDoc systemName) {
356         FileSystem fs = names.get(systemName);
357
358         return fs;
359     }
360
361     /** Saves pool to stream by saving all filesystems.
362     * The default (system) filesystem, or any persistent filesystems, are skipped.
363     *
364     * @param oos object output stream
365     * @exception IOException if an error occures
366     * @deprecated Unused.
367     */

368     @Deprecated JavaDoc
369     public final synchronized void writeExternal(ObjectOutput JavaDoc oos)
370     throws IOException JavaDoc {
371         Iterator JavaDoc iter = fileSystems.iterator();
372
373         while (iter.hasNext()) {
374             FileSystem fs = (FileSystem) iter.next();
375
376             if (!fs.isDefault() && !fs.isPersistent()) {
377                 oos.writeObject(new NbMarshalledObject(fs));
378             }
379         }
380
381         oos.writeObject(null);
382     }
383
384     /** Reads object from stream.
385     * Reads all filesystems. Persistent and system filesystems are untouched; all others are removed and possibly reread.
386     * @param ois object input stream
387     * @exception IOException if an error occures
388     * @exception ClassNotFoundException if read class is not found
389     * @deprecated Unused.
390     */

391     @Deprecated JavaDoc
392     public final synchronized void readExternal(ObjectInput JavaDoc ois)
393     throws IOException JavaDoc, ClassNotFoundException JavaDoc {
394         ArrayList JavaDoc<FileSystem> temp = new ArrayList JavaDoc<FileSystem>(10);
395
396         for (;;) {
397             Object JavaDoc obj = ois.readObject();
398
399             if (obj == null) {
400                 // all system has been read in
401
break;
402             }
403
404             FileSystem fs;
405
406             if (obj instanceof FileSystem) {
407                 fs = (FileSystem) obj;
408             } else {
409                 try {
410                     NbMarshalledObject mar = (NbMarshalledObject) obj;
411                     fs = (FileSystem) mar.get();
412                 } catch (IOException JavaDoc ex) {
413                     ExternalUtil.exception(ex);
414                     fs = null;
415                 } catch (ClassNotFoundException JavaDoc ex) {
416                     ExternalUtil.exception(ex);
417                     fs = null;
418                 }
419             }
420
421             if (fs != null) {
422                 // add the new filesystem
423
temp.add(fs);
424             }
425         }
426
427         Enumeration JavaDoc<? extends FileSystem> ee = getFileSystems();
428         FileSystem fs;
429
430         while (ee.hasMoreElements()) {
431             fs = ee.nextElement();
432
433             if (!fs.isPersistent()) {
434                 removeFileSystem(fs);
435             }
436         }
437
438         // in init assigned is checked and we force 'system' to be added again
439
system.assigned = false;
440         init();
441
442         // all is successfuly read
443
for (Iterator JavaDoc iter = temp.iterator(); iter.hasNext();)
444             addFileSystem((FileSystem) iter.next());
445     }
446
447     /** Finds file when its name is provided. It scans in the list of
448     * filesystems and asks them for the specified file by a call to
449     * {@link FileSystem#find find}. The first object that is found is returned or <CODE>null</CODE>
450     * if none of the filesystems contain such a file.
451     *
452     * @param aPackage package name where each package is separated by a dot
453     * @param name name of the file (without dots) or <CODE>null</CODE> if
454     * one wants to obtain the name of a package and not a file in it
455     * @param ext extension of the file or <CODE>null</CODE> if one needs
456     * a package and not a file name
457     *
458     * @return {@link FileObject} that represents file with given name or
459     * <CODE>null</CODE> if the file does not exist
460     * @deprecated Please use the <a HREF="@org-netbeans-api-java@/org/netbeans/api/java/classpath/ClassPath.html">ClassPath API</a> instead.
461     */

462     @Deprecated JavaDoc
463     public final FileObject find(String JavaDoc aPackage, String JavaDoc name, String JavaDoc ext) {
464         assert FileUtil.assertDeprecatedMethod();
465
466         Enumeration JavaDoc<? extends FileSystem> en = getFileSystems();
467
468         while (en.hasMoreElements()) {
469             FileSystem fs = en.nextElement();
470             FileObject fo = fs.find(aPackage, name, ext);
471
472             if (fo != null) {
473                 // object found
474
return fo;
475             }
476         }
477
478         return null;
479     }
480
481     /** Searches for the given resource among all filesystems.
482     * @see FileSystem#findResource
483     * @param name a name of the resource
484     * @return file object or <code>null</code> if the resource can not be found
485     * @deprecated Please use the <a HREF="@org-netbeans-api-java@/org/netbeans/api/java/classpath/ClassPath.html">ClassPath API</a> instead.
486     */

487     @Deprecated JavaDoc
488     public final FileObject findResource(String JavaDoc name) {
489         assert FileUtil.assertDeprecatedMethod();
490
491         Enumeration JavaDoc<? extends FileSystem> en = getFileSystems();
492
493         while (en.hasMoreElements()) {
494             FileSystem fs = en.nextElement();
495             FileObject fo = fs.findResource(name);
496
497             if (fo != null) {
498                 // object found
499
return fo;
500             }
501         }
502
503         return null;
504     }
505
506     /** Searches for the given resource among all filesystems, returning all matches.
507     * @param name name of the resource
508     * @return enumeration of {@link FileObject}s
509     * @deprecated Please use the <a HREF="@org-netbeans-api-java@/org/netbeans/api/java/classpath/ClassPath.html">ClassPath API</a> instead.
510     */

511     @Deprecated JavaDoc
512     public final Enumeration JavaDoc<? extends FileObject> findAllResources(String JavaDoc name) {
513         assert FileUtil.assertDeprecatedMethod();
514
515         Vector JavaDoc<FileObject> v = new Vector JavaDoc<FileObject>(8);
516         Enumeration JavaDoc<? extends FileSystem> en = getFileSystems();
517
518         while (en.hasMoreElements()) {
519             FileSystem fs = en.nextElement();
520             FileObject fo = fs.findResource(name);
521
522             if (fo != null) {
523                 v.addElement(fo);
524             }
525         }
526
527         return v.elements();
528     }
529
530     /** Finds all files among all filesystems matching a given name, returning all matches.
531     * All filesystems are queried with {@link FileSystem#find}.
532     *
533     * @param aPackage package name where each package is separated by a dot
534     * @param name name of the file (without dots) or <CODE>null</CODE> if
535     * one wants to obtain the name of a package and not a file in it
536     * @param ext extension of the file or <CODE>null</CODE> if one needs
537     * a package and not a file name
538     *
539     * @return enumeration of {@link FileObject}s
540     * @deprecated Please use the <a HREF="@org-netbeans-api-java@/org/netbeans/api/java/classpath/ClassPath.html">ClassPath API</a> instead.
541     */

542     @Deprecated JavaDoc
543     public final Enumeration JavaDoc<? extends FileObject> findAll(String JavaDoc aPackage, String JavaDoc name, String JavaDoc ext) {
544         assert FileUtil.assertDeprecatedMethod();
545
546         Enumeration JavaDoc<? extends FileSystem> en = getFileSystems();
547         Vector JavaDoc<FileObject> ret = new Vector JavaDoc<FileObject>();
548
549         while (en.hasMoreElements()) {
550             FileSystem fs = (FileSystem) en.nextElement();
551             FileObject fo = fs.find(aPackage, name, ext);
552
553             if (fo != null) {
554                 ret.addElement(fo);
555             }
556         }
557
558         return ret.elements();
559     }
560
561     /** Fire info about changes in the filesystem pool.
562     * @param fs filesystem
563     * @param add <CODE>true</CODE> if the filesystem is added,
564     * <CODE>false</CODE> if it is removed
565     */

566     private void fireFileSystem(FileSystem fs, boolean add) {
567         RepositoryEvent ev = new RepositoryEvent(this, fs, add);
568         for (RepositoryListener list : new HashSet JavaDoc<RepositoryListener>(listeners.values())) {
569             if (add) {
570                 list.fileSystemAdded(ev);
571             } else {
572                 list.fileSystemRemoved(ev);
573             }
574         }
575     }
576
577     /** Fires info about reordering
578     * @param perm
579     */

580     private void fireFileSystemReordered(int[] perm) {
581         RepositoryReorderedEvent ev = new RepositoryReorderedEvent(this, perm);
582         for (RepositoryListener list : new HashSet JavaDoc<RepositoryListener>(listeners.values())) {
583             list.fileSystemPoolReordered(ev);
584         }
585     }
586
587     /** Adds new listener.
588     * @param list the listener
589     * @deprecated Please use the <a HREF="@org-netbeans-api-java@/org/netbeans/api/java/classpath/ClassPath.html">ClassPath API</a> instead.
590     */

591     @Deprecated JavaDoc
592     public final void addRepositoryListener(RepositoryListener list) {
593         listeners.put(list, list);
594     }
595
596     /** Removes listener.
597     * @param list the listener
598     * @deprecated Please use the <a HREF="@org-netbeans-api-java@/org/netbeans/api/java/classpath/ClassPath.html">ClassPath API</a> instead.
599     */

600     @Deprecated JavaDoc
601     public final void removeRepositoryListener(RepositoryListener list) {
602         listeners.remove(list);
603     }
604
605     /** Writes the object to the stream.
606     */

607     private Object JavaDoc writeReplace() {
608         return new Replacer();
609     }
610
611     final FCLSupport getFCLSupport() {
612         synchronized (FCLSupport.class) {
613             if (fclSupport == null) {
614                 fclSupport = new FCLSupport();
615             }
616         }
617
618         return fclSupport;
619     }
620
621     /** Add new listener to this object.
622     * @param fcl the listener
623     * @since 2.8
624     * @deprecated useless because there is no filesystem but only
625     * default filesystem in Repository. Add new listener directly to
626     * default filesystem {@link #getDefaultFileSystem}.
627     */

628     @Deprecated JavaDoc
629     public final void addFileChangeListener(FileChangeListener fcl) {
630         getFCLSupport().addFileChangeListener(fcl);
631     }
632
633     /** Remove listener from this object.
634     * @param fcl the listener
635     * @since 2.8
636     * @deprecated useless because there is no filesystem but only
637     * default filesystem in Repository. Add new listener directly to
638     * default filesystem {@link #getDefaultFileSystem}.
639     */

640     @Deprecated JavaDoc
641     public final void removeFileChangeListener(FileChangeListener fcl) {
642         getFCLSupport().removeFileChangeListener(fcl);
643     }
644
645     private static class Replacer implements java.io.Serializable JavaDoc {
646         /** serial version UID */
647         static final long serialVersionUID = -3814531276726840241L;
648
649         Replacer() {
650         }
651
652         private void writeObject(ObjectOutputStream JavaDoc oos)
653         throws IOException JavaDoc {
654             ExternalUtil.getRepository().writeExternal(oos);
655         }
656
657         private void readObject(ObjectInputStream JavaDoc ois)
658         throws IOException JavaDoc, ClassNotFoundException JavaDoc {
659             ExternalUtil.getRepository().readExternal(ois);
660         }
661
662         /** @return the default pool */
663         public Object JavaDoc readResolve() {
664             return ExternalUtil.getRepository();
665         }
666     }
667 }
668
Popular Tags