1 package org.astrogrid.store.delegate.myspaceItn05;
2
3 import java.io.FileNotFoundException;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.OutputStream;
7 import java.lang.reflect.Array;
8 import java.net.InetAddress;
9 import java.net.MalformedURLException;
10 import java.net.URL;
11 import java.net.UnknownHostException;
12 import java.util.ArrayList;
13 import java.util.Date;
14 import java.util.Hashtable;
15 import java.util.StringTokenizer;
16 import javax.xml.rpc.ServiceException;
17 import org.apache.commons.logging.Log;
18 import org.apache.commons.logging.LogFactory;
19 import org.astrogrid.community.User;
20 import org.astrogrid.store.Agsl;
21 import org.astrogrid.store.Msrl;
22 import org.astrogrid.store.delegate.StoreAdminClient;
23 import org.astrogrid.store.delegate.StoreClient;
24 import org.astrogrid.store.delegate.StoreDelegateFactory;
25 import org.astrogrid.store.delegate.StoreException;
26 import org.astrogrid.store.delegate.StoreFile;
27
28
29 /***
30 * <code>MySpaceIt05Delegate</code> is the delegate class which
31 * applications invoke in order to access a MySpace service.
32 *
33 * @author A C Davenhall (Edinburgh)
34 * @author C L Qin (Leicester)
35 * @since Iteration 5. There has been a MySpace delegate since
36 * Iteration 2. The present delegate dates from Iteration 5.
37 * @version Iteration 5.
38 */
39
40
41
42
43
44 public class MySpaceIt05Delegate implements StoreClient, StoreAdminClient {
45
46 /***
47 * Commons logger
48 */
49 private static final Log logger = LogFactory.getLog(MySpaceIt05Delegate.class);
50
51 /*** Axis-generated binding = inner delegate */
52 private Manager innerDelegate = null;
53 /*** Location of Manager */
54 private Msrl managerMsrl = null;
55 /*** Account that is operating this delegate - eg user that is browsing myspace */
56 private User operator = null;
57
58 private boolean isTest = false;
59 private boolean throwExceptions = true;
60 private boolean allowOverWrite = true;
61
62 private ArrayList statusList = new ArrayList();
63
64
65
66
67
68
69
70 /***
71 * Constructs delegate that is operated by the given User, to connect to the
72 * MySpace Manager at the given endPoint.
73 */
74
75 public MySpaceIt05Delegate(User givenOperator, String givenEndPoint) throws IOException
76 {
77 this.operator = givenOperator;
78
79
80
81 if (!givenEndPoint.startsWith(Msrl.SCHEME)) {
82 givenEndPoint = Msrl.SCHEME+":"+givenEndPoint;
83 }
84
85 managerMsrl = new Msrl(givenEndPoint);
86
87 logger.debug("the endpoint in myspaceitn05delegate = " + managerMsrl.getDelegateEndpoint());
88 try
89 { ManagerService service = new ManagerServiceLocator();
90 innerDelegate = service.getAstrogridMyspace(managerMsrl.getDelegateEndpoint());
91 }
92 catch (ServiceException e)
93 { throw new IOException
94 ("Failed to connect to: " + givenEndPoint );
95 }
96 }
97
98
99
100
101
102
103
104
105
106
107
108 /***
109 * Specify whether the Manager is being used in test or genuine mode.
110 *
111 * In test mode the Manager will return standard responses, irrespective
112 * of whether it contains any entries. In genuine mode the Manager
113 * genuinely attempts to manipulate its data holdings.
114 *
115 * @param isTest Flag indicating whether in test or genuine mode: true for
116 * test mode and false otherwise.
117 */
118
119 public void setTest(boolean isTest)
120 { this.isTest = isTest;
121 }
122
123
124 /***
125 * Specify whether a bad status being returned by the Manager will
126 * cause the delegate to throw an exception.
127 *
128 * @param thowExceptions Flag indicating whether or not bad status
129 * returns cause an exception to be throw: true to throw exceptions
130 * and false otherwise.
131 */
132
133 public void setThrow(boolean throwExceptions)
134 { this.throwExceptions = throwExceptions;
135 }
136
137
138 /***
139 * Specify whether the Manager is allowed to overwrite an existing
140 * file when importing a new one.
141 *
142 * param allowOverWrite Flag indicating whether or not overwriting is
143 * allowed. True indicates that it is.
144 */
145
146 public void setOverWrite(boolean allowOverWrite)
147 { this.allowOverWrite = allowOverWrite;
148 }
149
150
151 /***
152 * Return a list of error codes accummulated by successive
153 * invocations of action methods.
154 *
155 * @return List of error codes, each of type <code>StatusMessage</code>.
156 */
157
158 public ArrayList getStatusList()
159 { return statusList;
160 }
161
162 /***
163 * Convenience method to list the error codes. The codes accummulated
164 * by successive invocations of action methods to standard output. Note
165 * that this method does not reset the list of error codes.
166 */
167
168 public void outputStatusList()
169 { int numMessages = statusList.size();
170
171 if (numMessages > 0)
172 { for(int loop=0; loop<numMessages; loop++)
173 { StatusMessage message =
174 (StatusMessage)statusList.get(loop);
175 logger.debug(message.toString() );
176 }
177 }
178 else
179 { logger.debug("No messages returned.");
180 }
181 }
182
183 /***
184 * Reset the list of error codes to contain zero entries.
185 */
186
187 public void resetStatusList()
188 { statusList.clear();
189 }
190
191
192
193
194
195
196
197
198
199 /***
200 * Return the User of this delegate - ie the account it is being used by
201 *
202 * @return The User of this delegate.
203 */
204 public User getOperator()
205 { return operator;
206 }
207
208
209
210 /***
211 * Return the Agsl of the service to which this client is connected.
212 *
213 * @return The Agsl of the service to which this client is connected.
214 */
215 public Agsl getEndpoint()
216 {
217 Agsl agsl = new Agsl( managerMsrl );
218 return agsl;
219 }
220
221
222
223
224 /***
225 * Helper function for converting EntryResults to MySpaceFile/Folder
226 * returns the name (ie last path token) of an EntryResults
227 */
228 public String getNameOf(EntryResults entryResult) {
229 String path = entryResult.getEntryName();
230
231
232
233 if (path.endsWith("/")) {
234 path = path.substring(0,path.length());
235 }
236
237 if (path.lastIndexOf("/") == -1) {
238 return path;
239 }
240
241 return path.substring(path.lastIndexOf("/")+1);
242 }
243
244 /***
245 * Helper function for converting EntryResults to MySpaceFile/Folder
246 * returns the path only (ie not including name) of an EntryResults
247 */
248 public String getParentPathOf(EntryResults entryResult) {
249 String fullPath = entryResult.getEntryName();
250
251
252
253 if (fullPath.endsWith("/")) {
254 fullPath = fullPath.substring(0,fullPath.length());
255 }
256
257 if (fullPath.lastIndexOf("/") == -1) {
258 return "";
259 }
260
261 return fullPath.substring(0,fullPath.lastIndexOf("/"));
262 }
263 /***
264 * Helper function for converting EntryResults to MySpaceFile/Folder
265 * Creates a MySpaceFile/Folder from the given entry result
266 */
267 public StoreFile makeStoreFile(MySpaceFolder parent, EntryResults result) {
268 logger
269 .info("makeStoreFile(MySpaceFolder, EntryResults) - FROG : makeStoreFile()");
270 logger.info("makeStoreFile(MySpaceFolder, EntryResults) - Name"
271 + result.getEntryName());
272 logger.info("makeStoreFile(MySpaceFolder, EntryResults) - Size"
273 + result.getSize());
274
275 StoreFile file;
276 if (result.getType() == EntryCodes.CON) {
277 if (parent == null) {
278 file = new MySpaceFolder();
279 }
280 else {
281 file = new MySpaceFolder(parent, result);
282 }
283 }
284 else {
285 if (parent == null) {
286
287 parent = new MySpaceFolder(getParentPathOf(result));
288
289 file = new MySpaceFile(parent, result);
290 }
291 else {
292 file = new MySpaceFile(parent, result);
293 }
294 }
295 logger.info("makeStoreFile(MySpaceFolder, EntryResults) - Size"
296 + file.getSize());
297 return file;
298 }
299
300 /***
301 * Return a tree representation of the files that match the expression
302 */
303
304 public StoreFile getFiles(String filter) throws IOException
305 {
306
307 KernelResults results = innerDelegate.getEntriesList(filter, isTest);
308
309 this.appendAndCheckStatusMessages(results);
310
311 if (results == null) {
312 return null;
313 }
314
315
316
317 Object[] fileList = results.getEntries();
318
319 if (fileList == null) {
320 return null;
321 }
322
323 MySpaceFolder root = new MySpaceFolder();
324
325
326 for (int r=0;r<fileList.length;r++) {
327
328 EntryResults result = (EntryResults) fileList[r];
329
330
331 MySpaceFolder parentFolder;
332
333 String path = result.getEntryName();
334
335
336 if (path.endsWith("/")) {
337 path = path.substring(0,path.length());
338 }
339
340 if (path.startsWith("/")) {
341 path = path.substring(1);
342 }
343 if (path.indexOf("/")==-1) {
344
345 parentFolder = root;
346 }
347 else {
348 String parentPath = path.substring(0, path.lastIndexOf("/"));
349 parentFolder = (MySpaceFolder) root.findFile(parentPath);
350 }
351
352
353
354 StoreFile file = makeStoreFile(parentFolder, result);
355 parentFolder.add(file);
356 }
357
358 return root;
359 }
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404 /***
405 * Returns the StoreFile representation of the file at the given AGSL
406 */
407
408 public StoreFile getFile(String path) throws IOException
409 {
410 logger.info("getFile(String) - FROG : getFile()");
411 logger.info("getFile(String) - Path" + path);
412
413 if (!path.startsWith("/")) path = "/"+path;
414
415 KernelResults results = innerDelegate.getEntriesList(path, isTest);
416
417
418
419
420 this.appendAndCheckStatusMessages(results);
421
422
423
424
425
426 if (results.getEntries() == null) {
427 return null;
428 }
429 else {
430 return makeStoreFile(null, (EntryResults) results.getEntries()[0]);
431 }
432 }
433
434
435 /***
436 * Returns the Agsl for the given source path. NB = no such thing for
437 * folders at the moment
438 */
439 public Agsl getAgsl(String sourcePath) throws IOException {
440 assert (!sourcePath.endsWith("/") && !sourcePath.endsWith("//")) : "Cannot create AGSLs for folders (yet)";
441
442 return new Agsl(getEndpoint(), sourcePath);
443 }
444
445
446
447
448
449 /***
450 * Put the given byte buffer from offset of length bytes, to the given target
451 */
452 public void putBytes(byte[] bytes, int offset, int length,
453 String targetPath, boolean append) throws IOException
454 {
455
456 if (!targetPath.startsWith("/")) targetPath = "/"+targetPath;
457
458
459
460
461 int dispatchExisting = ManagerCodes.LEAVE;
462 if (append)
463 { dispatchExisting = ManagerCodes.APPEND;
464 }
465 else
466 { if (this.allowOverWrite)
467 { dispatchExisting = ManagerCodes.OVERWRITE;
468 }
469 else
470 { dispatchExisting = ManagerCodes.LEAVE;
471 }
472 }
473
474
475
476
477 int numBytes = length - offset;
478 byte[] subsetToSend = new byte[length];
479
480 for (int loop=0; loop<numBytes; loop++)
481 { subsetToSend[loop] = bytes[loop + offset];
482 }
483
484
485
486
487
488
489
490
491 KernelResults results = innerDelegate.putBytes(targetPath,
492 subsetToSend, EntryCodes.UNKNOWN, dispatchExisting, isTest);
493
494
495
496
497 this.appendAndCheckStatusMessages(results);
498
499 }
500
501
502
503
504 /***
505 * Put the given string into the given location
506 */
507 public void putString(String contents, String targetPath, boolean append)
508 throws IOException
509 {
510
511 if (!targetPath.startsWith("/")) targetPath = "/"+targetPath;
512
513
514
515
516 int dispatchExisting = ManagerCodes.LEAVE;
517 if (append)
518 { dispatchExisting = ManagerCodes.APPEND;
519 }
520 else
521 { if (this.allowOverWrite)
522 { dispatchExisting = ManagerCodes.OVERWRITE;
523 }
524 else
525 { dispatchExisting = ManagerCodes.LEAVE;
526 }
527 }
528
529
530
531
532
533
534
535
536 KernelResults results = innerDelegate.putString(targetPath,
537 contents, EntryCodes.UNKNOWN, dispatchExisting, isTest);
538
539
540
541
542 this.appendAndCheckStatusMessages(results);
543
544 }
545
546
547
548
549 /***
550 * Copy the contents of the file at the given source url to the given
551 * location.
552 */
553 public void putUrl(URL source, String targetPath, boolean append)
554 throws IOException
555 {
556
557 if (!targetPath.startsWith("/")) targetPath = "/"+targetPath;
558
559
560
561
562 int dispatchExisting = ManagerCodes.LEAVE;
563 if (append)
564 { dispatchExisting = ManagerCodes.APPEND;
565 }
566 else
567 { if (this.allowOverWrite)
568 { dispatchExisting = ManagerCodes.OVERWRITE;
569 }
570 else
571 { dispatchExisting = ManagerCodes.LEAVE;
572 }
573 }
574
575
576
577
578
579
580
581
582 String uri = source.toString();
583 KernelResults results = innerDelegate.putUri(targetPath,
584 uri, EntryCodes.UNKNOWN, dispatchExisting, isTest);
585
586
587
588
589 this.appendAndCheckStatusMessages(results);
590
591 }
592
593
594
595
596 /***
597 * Streaming output - returns a stream that can be used to output to the
598 * given location.
599 */
600
601 public OutputStream putStream(String targetPath, boolean append)
602 throws IOException
603 {
604 if (!targetPath.startsWith("/")) targetPath = "/"+targetPath;
605
606 return new MySpaceOutputStream(targetPath, append);
607 }
608
609
610
611
612 /***
613 * Get a file's contents as a stream
614 */
615 public InputStream getStream(String sourcePath) throws IOException
616 {
617
618 if (!sourcePath.startsWith("/")) sourcePath = "/"+sourcePath;
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638 URL url = getUrl(sourcePath);
639
640 if (url == null)
641 { throw new FileNotFoundException(
642 "Failed to find URL for path: " + sourcePath+" on "+managerMsrl);
643 }
644
645 return url.openStream();
646 }
647
648
649
650
651 /***
652 * Get the URL to the given file. This is a short term method; urls are not
653 * appropriate to access private files
654 */
655
656 public URL getUrl(String path) throws IOException
657 {
658 logger.info("getUrl(String)");
659 logger.info("getUrl(String) - MySPaceDeletage.getUrl");
660 logger.info("getUrl(String) - Path" + path);
661
662 if (!path.startsWith("/")) path = "/"+path;
663
664 KernelResults results = innerDelegate.getEntriesList(path, isTest);
665
666 this.appendAndCheckStatusMessages(results);
667
668 if ((results == null) || (results.getEntries() == null)) {
669 return null;
670 }
671
672 Object[] entries = results.getEntries();
673 EntryResults entry = (EntryResults) entries[0];
674
675
676 URL url = new URL(entry.getEntryUri());
677 logger.info("getUrl(String) - URL " + url.toString());
678
679
680
681
682
683
684
685 String host = url.getHost();
686 logger.info("getUrl(String) - Host" + host);
687
688
689
690 if(host.equalsIgnoreCase("localhost")) {
691 String protocol = url.getProtocol();
692 int port = url.getPort();
693 String urlPath = url.getPath();
694
695 try {
696 InetAddress addr = InetAddress.getLocalHost();
697 String fullHostName = addr.getCanonicalHostName();
698 url = new URL(protocol, fullHostName, port, urlPath);
699 }
700 catch(UnknownHostException e) {
701
702 }
703 }
704
705 logger.info("getUrl(String) - URL " + url.toString());
706
707 return url;
708 }
709
710
711
712
713 /***
714 * Delete a file.
715 */
716
717 public void delete(String deletePath) throws IOException
718 {
719 if (!deletePath.startsWith("/")) deletePath = "/"+deletePath;
720
721 KernelResults results = innerDelegate.deleteFile(deletePath, isTest);
722
723
724
725
726 this.appendAndCheckStatusMessages(results);
727
728 }
729
730
731
732
733 /***
734 * Copy a file to a target Agsl.
735 * Because myspace can 'pull' better than push, this calls the target Agsl
736 * store (if different from this one) with a putUrl to the sourcepath
737 */
738
739 public void copy(String sourcePath, Agsl target) throws IOException
740 {
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765 logger.info("copy(String, Agsl) - ----");
766 logger.info("copy(String, Agsl) - MySpaceIt05Delegate.copy");
767 logger.info("copy(String, Agsl) - Source path : '" + sourcePath + "'");
768 logger.info("copy(String, Agsl) - Target agsl : '" + target.toString() + "'");
769
770 URL url = getUrl(sourcePath) ;
771
772 logger.info("copy(String, Agsl) - Source URL : '" + url.toString() + "'");
773
774 logger.info("copy(String, Agsl)");
775 logger.info("copy(String, Agsl) - Creating target delegate ....");
776 StoreClient targetStore =
777 StoreDelegateFactory.createDelegate(
778 operator,
779 target
780 );
781 logger.info("copy(String, Agsl) - Done");
782
783 logger.info("copy(String, Agsl)");
784 logger.info("copy(String, Agsl) - Calling target delegate ....");
785 targetStore.putUrl(
786 url,
787 target.getPath(),
788 false
789 );
790 logger.info("copy(String, Agsl) - Done");
791
792 }
793
794
795
796
797 /***
798 * Copy a file from a source Agsl.
799 */
800
801 public void copy(Agsl source, String targetPath) throws IOException
802 {
803 if (source.getEndpoint().equals(getEndpoint())) {
804 String sourcePath = source.getPath();
805 if (!targetPath.startsWith("/")) targetPath = "/"+targetPath;
806 if (!sourcePath.startsWith("/")) sourcePath = "/"+sourcePath;
807
808 KernelResults results = innerDelegate.copyFile(sourcePath, targetPath, isTest);
809
810
811
812
813 this.appendAndCheckStatusMessages(results);
814 }
815 else
816 {
817 StoreClient sourceStore = StoreDelegateFactory.createDelegate(operator, source);
818
819 putUrl(sourceStore.getUrl(source.getPath()), targetPath, false);
820 }
821 }
822
823
824
825 /***
826 * Move (or rename) a file to a target Agsl.
827 */
828
829 public void move(String sourcePath, Agsl target) throws IOException
830 {
831
832
833 copy(sourcePath, target);
834 delete(sourcePath);
835 }
836
837
838
839
840 /***
841 * Moves (or rename) a file from a source Agsl.
842 */
843
844 public void move(Agsl source, String targetPath) throws IOException
845 {
846
847
848 copy(source, targetPath);
849 StoreDelegateFactory.createDelegate(operator, source);
850 }
851
852
853
854
855 /***
856 * Create a container.
857 */
858
859 public void newFolder(String targetPath) throws IOException
860 {
861 if (!targetPath.startsWith("/")) targetPath = "/"+targetPath;
862
863 KernelResults results = innerDelegate.createContainer(targetPath, isTest);
864
865
866
867
868 this.appendAndCheckStatusMessages(results);
869 }
870
871
872
873
874
875
876
877
878
879 /***
880 * Create a new account on an MSS.
881 *
882 * <p>
883 * `Create a new account' is something of a misnomer. This method is
884 * really just creating the base set of containers which every account
885 * needs.
886 * </p>
887 *
888 * @param newAccount Account of the user to be created.
889 */
890
891 public void createUser(User newAccount) throws IOException
892 { String account = newAccount.getUserId();
893 KernelResults results = innerDelegate.createAccount(
894 account, isTest);
895
896
897
898
899 this.appendAndCheckStatusMessages(results);
900
901 }
902
903
904
905
906 /***
907 * Delete an account from an MSS.
908 *
909 * <p>
910 * `Delete an account' is something of a misnomer. The method merely
911 * removes all extant containers belonging to an account. Any files
912 * belonging to the account must have been removed previously. However,
913 * the method will remove any remaining arbitrarily complex tree of
914 * containers. If any files are found the account will be left
915 * untouched.
916 * </p>
917 *
918 * @param deadAccount Details of the account to be deleted.
919 */
920
921 public void deleteUser(User deadAccount) throws IOException
922 { String account = deadAccount.getUserId();
923 KernelResults results = innerDelegate.deleteAccount(
924 account, isTest);
925
926
927
928
929 this.appendAndCheckStatusMessages(results);
930
931 }
932
933
934
935
936
937
938
939
940 /***
941 * `Heart-beat' method to check whether the Manager is up and running.
942 *
943 * @return Return true if the Manager is responding; otherwise return
944 * false.
945 */
946
947 public boolean heartBeat() throws IOException
948 { boolean response = false;
949
950 try
951 { String result = innerDelegate.heartBeat();
952 if (result.equals("Adsum.") )
953 { response = true;
954 }
955 }
956 catch (Exception all)
957 { response = false;
958 }
959
960 return response;
961 }
962
963
964
965
966 /***
967 * Return the contents of a file as a String.
968 *
969 * @param targetPath Path to the file whose contents are to be
970 * retrieved.
971 * @return The contents of the file.
972 * @deprecated (extremely) - will break on large files. Use getStream() instead.
973 */
974 public String getString(String targetPath) throws IOException
975 { String contents = "";
976
977 if (!targetPath.startsWith("/")) targetPath = "/"+targetPath;
978
979
980
981 KernelResults results = innerDelegate.getString(targetPath, isTest);
982
983
984
985
986 if (results.getContentsString() != null)
987 { contents = results.getContentsString();
988 }
989
990
991
992
993 this.appendAndCheckStatusMessages(results);
994
995 return contents;
996 }
997
998
999
1000
1001 /***
1002 * Return the contents of a file as an array of bytes.
1003 *
1004 * @param targetPath Path to the file whose contents are to be
1005 * retrieved.
1006 * @return The contents of the file.
1007 * @deprecated (extremely) - will break on large files. Use getStream() instead.
1008 */
1009 public byte[] getBytes(String targetPath) throws IOException
1010 { byte[] contents = null;
1011
1012 if (!targetPath.startsWith("/")) targetPath = "/"+targetPath;
1013
1014
1015
1016 KernelResults results = innerDelegate.getBytes(targetPath,
1017 isTest);
1018
1019
1020
1021
1022 if (results.getContentsBytes() != null)
1023 { contents = results.getContentsBytes();
1024 }
1025
1026
1027
1028
1029 this.appendAndCheckStatusMessages(results);
1030
1031 return contents;
1032 }
1033
1034
1035
1036
1037 /***
1038 * Extend the lifetime of a file in an MSS.
1039 *
1040 * <p>
1041 * This method operates on multiple AGSLs by permitting wild-cards in
1042 * the AGSL path.
1043 * </p>
1044 *
1045 * @param fileName File name of the entry to be modified.
1046 * @param newExpiryDate New expiry date for the file.
1047 */
1048
1049 public void extendLifetime(String fileName, Date newExpiryDate)
1050 throws IOException
1051 { long expiry = newExpiryDate.getTime();
1052 KernelResults results = innerDelegate.extendLifetime(
1053 fileName, expiry, isTest);
1054
1055
1056
1057
1058 this.appendAndCheckStatusMessages(results);
1059
1060 }
1061
1062
1063
1064
1065 /***
1066 * Change the owner of a MySpace file.
1067 *
1068 * <p>
1069 * This method operates on multiple AGSLs by permitting wild-cards in
1070 * the AGSL path.
1071 * </p>
1072 *
1073 * @param path Path (incl wild cards) of fiels to be modified.
1074 * @param newOwner Account of the new owner.
1075 */
1076
1077 public void changeOwner(String path, User newOwner)
1078 throws IOException
1079 { String owner = newOwner.getAccount();
1080 KernelResults results = innerDelegate.changeOwner(
1081 path, owner, isTest);
1082
1083
1084
1085
1086 this.appendAndCheckStatusMessages(results);
1087
1088 }
1089
1090
1091
1092
1093
1094
1095
1096 /***
1097 * Given a results object returned by the inner delegate, the array
1098 * of status results are extracted, appended to the delegate's internal
1099 * list and checked to see whether any correspond to an error.
1100 *
1101 * @param results Results object returned by the inner delegate.
1102 */
1103
1104 private void appendAndCheckStatusMessages(KernelResults results)
1105 throws StoreException
1106 { boolean errorRaised = false;
1107 String messageFromManager = "none.";
1108
1109 Object[] statusResults = results.getStatusList();
1110 int numStatus = Array.getLength(statusResults);
1111
1112 if (numStatus > 0)
1113 { StatusMessage status = new StatusMessage();
1114
1115 for(int loop=0; loop<numStatus; loop++)
1116 {
1117
1118
1119
1120 status = new StatusMessage( (StatusResults)statusResults[loop] );
1121
1122
1123
1124
1125 this.statusList.add(status);
1126
1127
1128
1129
1130
1131 if (status.getSeverity() == StatusCodes.ERROR)
1132 { if (!errorRaised)
1133 { messageFromManager = status.getMessage();
1134 }
1135 errorRaised = true;
1136 }
1137 }
1138 }
1139
1140 if (errorRaised && throwExceptions)
1141 { throw new StoreException(messageFromManager);
1142 }
1143 }
1144
1145
1146
1147
1148 /***
1149 * Special OutputStream which writes to a String, then sends it when the
1150 * stream is closed.
1151 */
1152
1153 private class MySpaceOutputStream extends OutputStream
1154 {
1155 /***
1156 * Commons Logger for this class
1157 */
1158 private final Log logger = LogFactory.getLog(MySpaceOutputStream.class);
1159 private String targetPath = null;
1160
1161 private byte[] buffer = new byte[32000];
1162 private int cursor = 0;
1163
1164
1165 public MySpaceOutputStream(String aTargetPath, boolean append)
1166 throws IOException
1167 { this.targetPath = aTargetPath;
1168
1169
1170
1171
1172
1173 if (!append)
1174 { putString("", targetPath, false);
1175 }
1176 }
1177
1178 /*** OutputStream method implementation. All writes go through this method -
1179 * it batches up the low byte of each character 'i' into a buffer, and
1180 * when the buffer is full 'flushes' it to the server using writeString()
1181 * with append on.
1182 */
1183 public void write(int i) throws IOException
1184 {
1185
1186
1187
1188 buffer[cursor] = (byte) (i & 0xFF);
1189
1190 cursor++;
1191 if (cursor >= buffer.length)
1192 { flush();
1193 }
1194 }
1195
1196
1197 public void flush() throws IOException
1198 {
1199
1200
1201
1202 putBytes(buffer, 0, cursor, targetPath, true);
1203
1204 cursor=0;
1205 }
1206
1207 /*** For human readable debugging */
1208 public String toString() {
1209 return "MySpaceOutputStream ["+managerMsrl+"#"+targetPath+"]";
1210 }
1211
1212 public void close() throws IOException
1213 { flush();
1214 super.close();
1215 }
1216 }
1217
1218
1219 /***
1220 * Inner class that implements StoreFile. It's useful to have it as an
1221 * inner class so that it can access private methods of the delegate to
1222 * getParent, children, etc
1223 */
1224 private class MySpaceFile implements StoreFile {
1225 /***
1226 * Commons Logger for this class
1227 */
1228 private final Log logger = LogFactory.getLog(MySpaceFile.class);
1229
1230 String name = null;
1231 String owner = null;
1232 Date created = null;
1233 Date expires = null;
1234 long size = -1;
1235 String permissions = null;
1236 URL url = null;
1237
1238 String mime = null ;
1239 MySpaceFileType type = null;
1240 MySpaceFolder parentFolder = null;
1241
1242 /*** Constructs an empty file - suitable eg for root */
1243 private MySpaceFile() {
1244 }
1245
1246 /***
1247 * Constructs a file from the given parent folder and the axis-generated
1248 * class returned by the binding
1249 */
1250 public MySpaceFile(MySpaceFolder parent, EntryResults bindingEntry) {
1251
1252 this.parentFolder = parent;
1253 this.name = getNameOf(bindingEntry);
1254
1255 this.owner = bindingEntry.getOwnerId();
1256 this.created = new Date(bindingEntry.getCreationDate());
1257 this.expires = new Date(bindingEntry.getExpiryDate());
1258 this.size = bindingEntry.getSize();
1259 this.permissions = bindingEntry.getPermissionsMask();
1260 this.mime = bindingEntry.getMime() ;
1261 this.type = MySpaceFileType.getForManagerRef(bindingEntry.getType());
1262 try {
1263 this.url = new URL(bindingEntry.getEntryUri());
1264 }
1265 catch (MalformedURLException mue) {
1266
1267 logger.error("Server returned invalid URL "+bindingEntry.getEntryUri()+" for entry "+bindingEntry.getEntryName());
1268 }
1269 }
1270
1271 public String getType() { return type.toString(); }
1272
1273 public String toString() { return getName(); }
1274
1275 public String getOwner() { return owner; }
1276
1277 /*** Returns the date the file was created */
1278 public Date getCreated() { return created; }
1279
1280 public Date getExpires() { return expires; }
1281
1282 public long getSize() { return size; }
1283
1284 public String getPermissions() { return permissions; }
1285
1286 /*** Returns the mime type (null if unknown) */
1287 public String getMimeType() { return mime ; }
1288
1289 /*** Returns the date the file was last modified (null if unknown) */
1290 public Date getModified() { return null; }
1291
1292 /*** Returns URL to the file */
1293 public URL getUrl() { return url; }
1294
1295 /*** Returns the path to this file on the server including filename */
1296 public String getPath() {
1297 return getParent().getPath()+name;
1298 }
1299
1300 /*** Returns true if this is a container that can hold other files/folders */
1301 public boolean isFolder() { return false; }
1302
1303 /*** Returns true if this is a self-contained file. For example, a database
1304 * table might be represented as a StoreFile but it is not a file */
1305 public boolean isFile() { return true; }
1306
1307 /*** Returns file or folder name */
1308 public String getName() {
1309 return name;
1310 }
1311
1312 /*** Returns the parent folder */
1313 public StoreFile getParent() {
1314 return parentFolder;
1315 }
1316
1317
1318 /*** Lists children files if this is a container - returns null otherwise */
1319 public StoreFile[] listFiles() { return null; }
1320
1321 /*** Returns true if this represents the same file as the given one */
1322 public boolean equals(StoreFile anotherFile) {
1323 if (anotherFile instanceof MySpaceFile) {
1324 return name.equals( ((MySpaceFile) anotherFile).name) &&
1325 parentFolder.equals(((MySpaceFile) anotherFile).parentFolder);
1326 }
1327 return false;
1328 }
1329 }
1330
1331 /***
1332 * Represents a folder in myspace.
1333 * See also comments on @link MySpaceFile
1334 *
1335 * @author mch
1336 */
1337 private class MySpaceFolder extends MySpaceFile {
1338 /***
1339 * Commons Logger for this class
1340 */
1341 private final Log logger = LogFactory.getLog(MySpaceFolder.class);
1342
1343 Hashtable children = new Hashtable();
1344
1345 boolean isRoot = false;
1346
1347 /*** Creates a folder that is a child of another one. */
1348 public MySpaceFolder(MySpaceFolder parent, EntryResults bindingEntry) {
1349 super(parent, bindingEntry);
1350 }
1351
1352 /*** Creates the root folder */
1353 public MySpaceFolder() {
1354 super();
1355 isRoot = true;
1356 }
1357
1358 /*** Creates a folder from a path */
1359 public MySpaceFolder(String givenPath) {
1360 super();
1361 if (givenPath.startsWith("/")) {
1362 givenPath = givenPath.substring(1);
1363 }
1364 this.name = givenPath;
1365 }
1366
1367 /*** Adds the given StoreFile as a child that exists in this folder */
1368 public void add(StoreFile child) {
1369 children.put(child.getName(), child);
1370 }
1371
1372 /*** Returns the StoreFile representation of the child with the given filename */
1373 public StoreFile getChild(String filename) {
1374 return (StoreFile) children.get(filename);
1375 }
1376
1377 /*** Returns an array of the files in this container */
1378 public StoreFile[] listFiles() {
1379 return (StoreFile[]) (children.values().toArray(new StoreFile[] {}));
1380 }
1381
1382 /*** Returns path on server */
1383 public String getPath() {
1384 if (isRoot) {
1385 return "";
1386 }
1387 else {
1388 if (getParent() == null) {
1389
1390 return getName()+"/";
1391 }
1392 else {
1393 return getParent().getPath()+getName()+"/";
1394 }
1395 }
1396 }
1397
1398 /*** Returns true - this is a container */
1399 public boolean isFolder() { return true; }
1400
1401 /*** Returns false - this is a container */
1402 public boolean isFile() { return false; }
1403
1404 /***
1405 * Returns the folder or file matching the given path in the *children* of
1406 * this folder. So if the path is '/famous/stuff/main/' the returned StoreFile
1407 * will be the MySpaceFolder instance representing the 'main' directory
1408 */
1409 public StoreFile findFile(String path) throws FileNotFoundException {
1410
1411
1412 StringTokenizer dirTokens = new StringTokenizer(path, "/");
1413 MySpaceFolder folder = this;
1414 StoreFile child = null;
1415 while (dirTokens.hasMoreTokens())
1416 {
1417 String token = dirTokens.nextToken();
1418 child = folder.getChild(token);
1419 if (child == null) {
1420 throw new FileNotFoundException("No such token '"+token+"' in path '"+path+"' from "+this);
1421 }
1422 else {
1423 if (child.isFolder()) {
1424 folder = (MySpaceFolder) child;
1425 }
1426 }
1427 }
1428
1429 if (dirTokens.hasMoreTokens()) {
1430 throw new FileNotFoundException("path "+path+" only partly found from "+this);
1431 }
1432
1433 return child;
1434
1435 }
1436
1437 }
1438 }
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554