KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > alfresco > repo > content > AbstractContentReadWriteTest


1 /*
2  * Copyright (C) 2005 Alfresco, Inc.
3  *
4  * Licensed under the Mozilla Public License version 1.1
5  * with a permitted attribution clause. You may obtain a
6  * copy of the License at
7  *
8  * http://www.alfresco.org/legal/license.txt
9  *
10  * Unless required by applicable law or agreed to in writing,
11  * software distributed under the License is distributed on an
12  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific
14  * language governing permissions and limitations under the
15  * License.
16  */

17 package org.alfresco.repo.content;
18
19 import java.io.ByteArrayInputStream JavaDoc;
20 import java.io.ByteArrayOutputStream JavaDoc;
21 import java.io.File JavaDoc;
22 import java.io.FileInputStream JavaDoc;
23 import java.io.FileOutputStream JavaDoc;
24 import java.io.InputStream JavaDoc;
25 import java.io.OutputStream JavaDoc;
26 import java.nio.ByteBuffer JavaDoc;
27 import java.nio.channels.FileChannel JavaDoc;
28 import java.nio.channels.ReadableByteChannel JavaDoc;
29 import java.util.Date JavaDoc;
30 import java.util.Set JavaDoc;
31
32 import javax.transaction.UserTransaction JavaDoc;
33
34 import junit.framework.TestCase;
35
36 import org.alfresco.repo.transaction.DummyTransactionService;
37 import org.alfresco.service.cmr.repository.ContentIOException;
38 import org.alfresco.service.cmr.repository.ContentReader;
39 import org.alfresco.service.cmr.repository.ContentStreamListener;
40 import org.alfresco.service.cmr.repository.ContentWriter;
41 import org.alfresco.service.transaction.TransactionService;
42 import org.alfresco.util.ApplicationContextHelper;
43 import org.springframework.context.ApplicationContext;
44
45 /**
46  * Abstract base class that provides a set of tests for implementations
47  * of the content readers and writers.
48  *
49  * @see org.alfresco.service.cmr.repository.ContentReader
50  * @see org.alfresco.service.cmr.repository.ContentWriter
51  *
52  * @author Derek Hulley
53  */

54 public abstract class AbstractContentReadWriteTest extends TestCase
55 {
56     private static final ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
57     
58     protected TransactionService transactionService;
59     private String JavaDoc contentUrl;
60     private UserTransaction JavaDoc txn;
61     
62     public AbstractContentReadWriteTest()
63     {
64         super();
65     }
66
67     @Override JavaDoc
68     public void setUp() throws Exception JavaDoc
69     {
70         contentUrl = AbstractContentStore.createNewUrl();
71         transactionService = (TransactionService) ctx.getBean("TransactionService");
72         txn = transactionService.getUserTransaction();
73         txn.begin();
74     }
75     
76     public void tearDown() throws Exception JavaDoc
77     {
78         txn.rollback();
79     }
80     
81     /**
82      * Fetch the store to be used during a test. This method is invoked once per test - it is
83      * therefore safe to use <code>setUp</code> to initialise resources.
84      * <p>
85      * Usually tests will construct a static instance of the store to use throughout all the
86      * tests.
87      *
88      * @return Returns the <b>same instance</b> of a store for all invocations.
89      */

90     protected abstract ContentStore getStore();
91     
92     /**
93      * @see #getStore()
94      */

95     protected final ContentWriter getWriter()
96     {
97         return getStore().getWriter(null, contentUrl);
98     }
99     
100     /**
101      * @see #getStore()
102      */

103     protected final ContentReader getReader()
104     {
105         return getStore().getReader(contentUrl);
106     }
107     
108     public void testSetUp() throws Exception JavaDoc
109     {
110         assertNotNull("setUp() not executed: no content URL present");
111         
112         // check that the store remains the same
113
ContentStore store = getStore();
114         assertNotNull("No store provided", store);
115         assertTrue("The same instance of the store must be returned for getStore", store == getStore());
116     }
117     
118     public void testContentUrl() throws Exception JavaDoc
119     {
120         ContentReader reader = getReader();
121         ContentWriter writer = getWriter();
122         
123         // the contract is that both the reader and writer must refer to the same
124
// content -> the URL must be the same
125
String JavaDoc readerContentUrl = reader.getContentUrl();
126         String JavaDoc writerContentUrl = writer.getContentUrl();
127         assertNotNull("Reader url is invalid", readerContentUrl);
128         assertNotNull("Writer url is invalid", writerContentUrl);
129         assertEquals("Reader and writer must reference same content",
130                 readerContentUrl,
131                 writerContentUrl);
132         
133         // check that the content URL is correct
134
assertTrue("Content URL doesn't start with correct prefix",
135                 readerContentUrl.startsWith(ContentStore.STORE_PROTOCOL));
136     }
137     
138     public void testMimetypeAndEncoding() throws Exception JavaDoc
139     {
140         ContentWriter writer = getWriter();
141         // set mimetype and encoding
142
writer.setMimetype("text/plain");
143         writer.setEncoding("UTF-16");
144         
145         // create a UTF-16 string
146
String JavaDoc content = "A little bit o' this and a little bit o' that";
147         byte[] bytesUtf16 = content.getBytes("UTF-16");
148         // write the bytes directly to the writer
149
OutputStream JavaDoc os = writer.getContentOutputStream();
150         os.write(bytesUtf16);
151         os.close();
152         
153         // now get a reader from the writer
154
ContentReader reader = writer.getReader();
155         assertEquals("Writer -> Reader content URL mismatch", writer.getContentUrl(), reader.getContentUrl());
156         assertEquals("Writer -> Reader mimetype mismatch", writer.getMimetype(), reader.getMimetype());
157         assertEquals("Writer -> Reader encoding mismatch", writer.getEncoding(), reader.getEncoding());
158         
159         // now get the string directly from the reader
160
String JavaDoc contentCheck = reader.getContentString(); // internally it should have taken care of the encoding
161
assertEquals("Encoding and decoding of strings failed", content, contentCheck);
162     }
163     
164     public void testExists() throws Exception JavaDoc
165     {
166         ContentStore store = getStore();
167         
168         // make up a URL
169
String JavaDoc contentUrl = AbstractContentStore.createNewUrl();
170         
171         // it should not exist in the store
172
assertFalse("Store exists fails with new URL", store.exists(contentUrl));
173         
174         // get a reader
175
ContentReader reader = store.getReader(contentUrl);
176         assertNotNull("Reader must be present, even for missing content", reader);
177         assertFalse("Reader exists failure", reader.exists());
178         
179         // write something
180
ContentWriter writer = store.getWriter(null, contentUrl);
181         writer.putContent("ABC");
182         
183         assertTrue("Store exists should show URL to be present", store.exists(contentUrl));
184     }
185     
186     public void testGetReader() throws Exception JavaDoc
187     {
188         ContentWriter writer = getWriter();
189         
190         // check that no reader is available from the writer just yet
191
ContentReader nullReader = writer.getReader();
192         assertNull("No reader expected", nullReader);
193         
194         String JavaDoc content = "ABC";
195         // write some content
196
// long before = System.currentTimeMillis();
197
writer.setMimetype("text/plain");
198         writer.setEncoding("UTF-8");
199         writer.putContent(content);
200 // long after = System.currentTimeMillis();
201

202         // get a reader from the writer
203
ContentReader readerFromWriter = writer.getReader();
204         assertEquals("URL incorrect", writer.getContentUrl(), readerFromWriter.getContentUrl());
205         assertEquals("Mimetype incorrect", writer.getMimetype(), readerFromWriter.getMimetype());
206         assertEquals("Encoding incorrect", writer.getEncoding(), readerFromWriter.getEncoding());
207         
208         // get another reader from the reader
209
ContentReader readerFromReader = readerFromWriter.getReader();
210         assertEquals("URL incorrect", writer.getContentUrl(), readerFromReader.getContentUrl());
211         assertEquals("Mimetype incorrect", writer.getMimetype(), readerFromReader.getMimetype());
212         assertEquals("Encoding incorrect", writer.getEncoding(), readerFromReader.getEncoding());
213         
214         // check the content
215
String JavaDoc contentCheck = readerFromWriter.getContentString();
216         assertEquals("Content is incorrect", content, contentCheck);
217         
218         // check that the length is correct
219
int length = content.getBytes(writer.getEncoding()).length;
220         assertEquals("Reader content length is incorrect", length, readerFromWriter.getSize());
221
222 //
223
// This check has been disabled as Linux is out by some variable amount of time
224
// // check that the last modified time is correct
225
// long modifiedTimeCheck = readerFromWriter.getLastModified();
226
// assertTrue("Reader last modified is incorrect", before <= modifiedTimeCheck);
227
// assertTrue("Reader last modified is incorrect", modifiedTimeCheck <= after);
228
//
229
}
230     
231     public void testClosedState() throws Exception JavaDoc
232     {
233         ContentReader reader = getReader();
234         ContentWriter writer = getWriter();
235         
236         // check that streams are not flagged as closed
237
assertFalse("Reader stream should not be closed", reader.isClosed());
238         assertFalse("Writer stream should not be closed", writer.isClosed());
239         
240         // check that the write doesn't supply a reader
241
ContentReader writerGivenReader = writer.getReader();
242         assertNull("No reader should be available before a write has finished", writerGivenReader);
243         
244         // write some stuff
245
writer.putContent("ABC");
246         // check that the write has been closed
247
assertTrue("Writer stream should be closed", writer.isClosed());
248         
249         // check that we can get a reader from the writer
250
writerGivenReader = writer.getReader();
251         assertNotNull("No reader given by closed writer", writerGivenReader);
252         assertFalse("Readers should still be closed", reader.isClosed());
253         assertFalse("Readers should still be closed", writerGivenReader.isClosed());
254         
255         // check that the instance is new each time
256
ContentReader newReaderA = writer.getReader();
257         ContentReader newReaderB = writer.getReader();
258         assertFalse("Reader must always be a new instance", newReaderA == newReaderB);
259         
260         // check that the readers refer to the same URL
261
assertEquals("Readers should refer to same URL",
262                 reader.getContentUrl(), writerGivenReader.getContentUrl());
263         
264         // read their content
265
String JavaDoc contentCheck = reader.getContentString();
266         assertEquals("Incorrect content", "ABC", contentCheck);
267         contentCheck = writerGivenReader.getContentString();
268         assertEquals("Incorrect content", "ABC", contentCheck);
269         
270         // check closed state of readers
271
assertTrue("Reader should be closed", reader.isClosed());
272         assertTrue("Reader should be closed", writerGivenReader.isClosed());
273     }
274     
275     /**
276      * Checks that the store disallows concurrent writers to be issued to the same URL.
277      */

278     public void testConcurrentWriteDetection() throws Exception JavaDoc
279     {
280         String JavaDoc contentUrl = AbstractContentStore.createNewUrl();
281         ContentStore store = getStore();
282
283         ContentWriter firstWriter = store.getWriter(null, contentUrl);
284         try
285         {
286             ContentWriter secondWriter = store.getWriter(null, contentUrl);
287             fail("Store issued two writers for the same URL: " + store);
288         }
289         catch (ContentIOException e)
290         {
291             // expected
292
}
293     }
294     
295     /**
296      * Checks that the writer can have a listener attached
297      */

298     public void testWriteStreamListener() throws Exception JavaDoc
299     {
300         ContentWriter writer = getWriter();
301         
302         final boolean[] streamClosed = new boolean[] {false}; // has to be final
303
ContentStreamListener listener = new ContentStreamListener()
304         {
305             public void contentStreamClosed() throws ContentIOException
306             {
307                 streamClosed[0] = true;
308             }
309         };
310         writer.setTransactionService(new DummyTransactionService());
311         writer.addListener(listener);
312         
313         // write some content
314
writer.putContent("ABC");
315         
316         // check that the listener was called
317
assertTrue("Write stream listener was not called for the stream close", streamClosed[0]);
318     }
319     
320     /**
321      * The simplest test. Write a string and read it again, checking that we receive the same values.
322      * If the resource accessed by {@link #getReader()} and {@link #getWriter()} is not the same, then
323      * values written and read won't be the same.
324      */

325     public void testWriteAndReadString() throws Exception JavaDoc
326     {
327         ContentReader reader = getReader();
328         ContentWriter writer = getWriter();
329         
330         String JavaDoc content = "ABC";
331         writer.putContent(content);
332         assertTrue("Stream close not detected", writer.isClosed());
333
334         String JavaDoc check = reader.getContentString();
335         assertTrue("Read and write may not share same resource", check.length() > 0);
336         assertEquals("Write and read didn't work", content, check);
337     }
338     
339     public void testStringTruncation() throws Exception JavaDoc
340     {
341         String JavaDoc content = "1234567890";
342         
343         ContentWriter writer = getWriter();
344         writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
345         writer.setEncoding("UTF-8"); // shorter format i.t.o. bytes used
346
// write the content
347
writer.putContent(content);
348         
349         // get a reader - get it in a larger format i.t.o. bytes
350
ContentReader reader = writer.getReader();
351         String JavaDoc checkContent = reader.getContentString(5);
352         assertEquals("Truncated strings don't match", "12345", checkContent);
353     }
354     
355     public void testReadAndWriteFile() throws Exception JavaDoc
356     {
357         ContentReader reader = getReader();
358         ContentWriter writer = getWriter();
359         
360         File JavaDoc sourceFile = File.createTempFile(getName(), ".txt");
361         sourceFile.deleteOnExit();
362         // dump some content into the temp file
363
String JavaDoc content = "ABC";
364         FileOutputStream JavaDoc os = new FileOutputStream JavaDoc(sourceFile);
365         os.write(content.getBytes());
366         os.flush();
367         os.close();
368         
369         // put our temp file's content
370
writer.putContent(sourceFile);
371         assertTrue("Stream close not detected", writer.isClosed());
372         
373         // create a sink temp file
374
File JavaDoc sinkFile = File.createTempFile(getName(), ".txt");
375         sinkFile.deleteOnExit();
376         
377         // get the content into our temp file
378
reader.getContent(sinkFile);
379         
380         // read the sink file manually
381
FileInputStream JavaDoc is = new FileInputStream JavaDoc(sinkFile);
382         byte[] buffer = new byte[100];
383         int count = is.read(buffer);
384         assertEquals("No content read", 3, count);
385         is.close();
386         String JavaDoc check = new String JavaDoc(buffer, 0, count);
387         
388         assertEquals("Write out of and read into files failed", content, check);
389     }
390     
391     public void testReadAndWriteStreamByPull() throws Exception JavaDoc
392     {
393         ContentReader reader = getReader();
394         ContentWriter writer = getWriter();
395
396         String JavaDoc content = "ABC";
397         // put the content using a stream
398
InputStream JavaDoc is = new ByteArrayInputStream JavaDoc(content.getBytes());
399         writer.putContent(is);
400         assertTrue("Stream close not detected", writer.isClosed());
401         
402         // get the content using a stream
403
ByteArrayOutputStream JavaDoc os = new ByteArrayOutputStream JavaDoc(100);
404         reader.getContent(os);
405         byte[] bytes = os.toByteArray();
406         String JavaDoc check = new String JavaDoc(bytes);
407         
408         assertEquals("Write out and read in using streams failed", content, check);
409     }
410     
411     public void testReadAndWriteStreamByPush() throws Exception JavaDoc
412     {
413         ContentReader reader = getReader();
414         ContentWriter writer = getWriter();
415
416         String JavaDoc content = "ABC";
417         // get the content output stream
418
OutputStream JavaDoc os = writer.getContentOutputStream();
419         os.write(content.getBytes());
420         assertFalse("Stream has not been closed", writer.isClosed());
421         // close the stream and check again
422
os.close();
423         assertTrue("Stream close not detected", writer.isClosed());
424         
425         // pull the content from a stream
426
InputStream JavaDoc is = reader.getContentInputStream();
427         byte[] buffer = new byte[100];
428         int count = is.read(buffer);
429         assertEquals("No content read", 3, count);
430         is.close();
431         String JavaDoc check = new String JavaDoc(buffer, 0, count);
432         
433         assertEquals("Write out of and read into files failed", content, check);
434     }
435     
436     /**
437      * Tests deletion of content.
438      * <p>
439      * Only applies when {@link #getStore()} returns a value.
440      */

441     public void testDelete() throws Exception JavaDoc
442     {
443         ContentStore store = getStore();
444         ContentWriter writer = getWriter();
445         
446         String JavaDoc content = "ABC";
447         String JavaDoc contentUrl = writer.getContentUrl();
448
449         // write some bytes, but don't close the stream
450
OutputStream JavaDoc os = writer.getContentOutputStream();
451         os.write(content.getBytes());
452         os.flush(); // make sure that the bytes get persisted
453

454         // close the stream
455
os.close();
456         
457         // get a reader
458
ContentReader reader = store.getReader(contentUrl);
459         assertNotNull(reader);
460         
461         ContentReader readerCheck = writer.getReader();
462         assertNotNull(readerCheck);
463         assertEquals("Store and write provided readers onto different URLs",
464                 writer.getContentUrl(), reader.getContentUrl());
465         
466         // open the stream onto the content
467
InputStream JavaDoc is = reader.getContentInputStream();
468         
469         // attempt to delete the content
470
boolean deleted = store.delete(contentUrl);
471
472         // close the reader stream
473
is.close();
474         
475         // get a fresh reader
476
reader = store.getReader(contentUrl);
477         assertNotNull(reader);
478         
479         // the underlying system may or may not have deleted the content
480
if (deleted)
481         {
482             assertFalse("Content should not exist", reader.exists());
483             // drop out here
484
return;
485         }
486         else
487         {
488             assertTrue("Content should exist", reader.exists());
489         }
490         
491         // delete the content
492
store.delete(contentUrl);
493         
494         // attempt to read from the reader
495
try
496         {
497             is = reader.getContentInputStream();
498             fail("Reader failed to detect underlying content deletion");
499         }
500         catch (ContentIOException e)
501         {
502             // expected
503
}
504         
505         // get another fresh reader
506
reader = store.getReader(contentUrl);
507         assertNotNull("Reader must be returned even when underlying content is missing",
508                 reader);
509         assertFalse("Content should not exist", reader.exists());
510         try
511         {
512             is = reader.getContentInputStream();
513             fail("Reader opened stream onto missing content");
514         }
515         catch (ContentIOException e)
516         {
517             // expected
518
}
519     }
520     
521     /**
522      * Tests retrieval of all content URLs
523      * <p>
524      * Only applies when {@link #getStore()} returns a value.
525      */

526     public void testListUrls() throws Exception JavaDoc
527     {
528         ContentStore store = getStore();
529
530         ContentWriter writer = getWriter();
531         
532         Set JavaDoc<String JavaDoc> contentUrls = store.getUrls();
533         String JavaDoc contentUrl = writer.getContentUrl();
534         assertTrue("Writer URL not listed by store", contentUrls.contains(contentUrl));
535
536         Date JavaDoc yesterday = new Date JavaDoc(System.currentTimeMillis() - 3600L * 1000L * 24L);
537         
538         // write some data
539
writer.putContent("The quick brown fox...");
540
541         // check again
542
contentUrls = store.getUrls();
543         assertTrue("Writer URL not listed by store", contentUrls.contains(contentUrl));
544         
545         // check that the query for content created before this time yesterday doesn't return the URL
546
contentUrls = store.getUrls(null, yesterday);
547         assertFalse("URL was younger than required, but still shows up", contentUrls.contains(contentUrl));
548         
549         // delete the content
550
boolean deleted = store.delete(contentUrl);
551         if (deleted)
552         {
553             contentUrls = store.getUrls();
554             assertFalse("Successfully deleted URL still shown by store", contentUrls.contains(contentUrl));
555         }
556     }
557     
558     /**
559      * Tests random access writing
560      * <p>
561      * Only executes if the writer implements {@link RandomAccessContent}.
562      */

563     public void testRandomAccessWrite() throws Exception JavaDoc
564     {
565         ContentWriter writer = getWriter();
566         
567         FileChannel JavaDoc fileChannel = writer.getFileChannel(true);
568         assertNotNull("No channel given", fileChannel);
569         
570         // check that no other content access is allowed
571
try
572         {
573             writer.getWritableChannel();
574             fail("Second channel access allowed");
575         }
576         catch (RuntimeException JavaDoc e)
577         {
578             // expected
579
}
580         
581         // write some content in a random fashion (reverse order)
582
byte[] content = new byte[] {1, 2, 3};
583         for (int i = content.length - 1; i >= 0; i--)
584         {
585             ByteBuffer JavaDoc buffer = ByteBuffer.wrap(content, i, 1);
586             fileChannel.write(buffer, i);
587         }
588         
589         // close the channel
590
fileChannel.close();
591         assertTrue("Writer not closed", writer.isClosed());
592         
593         // check the content
594
ContentReader reader = writer.getReader();
595         ReadableByteChannel JavaDoc channelReader = reader.getReadableChannel();
596         ByteBuffer JavaDoc buffer = ByteBuffer.allocateDirect(3);
597         int count = channelReader.read(buffer);
598         assertEquals("Incorrect number of bytes read", 3, count);
599         for (int i = 0; i < content.length; i++)
600         {
601             assertEquals("Content doesn't match", content[i], buffer.get(i));
602         }
603         
604         // get a new writer from the store, using the existing content and perform a truncation check
605
ContentWriter writerTruncate = getStore().getWriter(writer.getReader(), AbstractContentStore.createNewUrl());
606         assertEquals("Content size incorrect", 0, writerTruncate.getSize());
607         // get the channel with truncation
608
FileChannel JavaDoc fcTruncate = writerTruncate.getFileChannel(true);
609         fcTruncate.close();
610         assertEquals("Content not truncated", 0, writerTruncate.getSize());
611         
612         // get a new writer from the store, using the existing content and perform a non-truncation check
613
ContentWriter writerNoTruncate = getStore().getWriter(writer.getReader(), AbstractContentStore.createNewUrl());
614         assertEquals("Content size incorrect", 0, writerNoTruncate.getSize());
615         // get the channel without truncation
616
FileChannel JavaDoc fcNoTruncate = writerNoTruncate.getFileChannel(false);
617         fcNoTruncate.close();
618         assertEquals("Content was truncated", writer.getSize(), writerNoTruncate.getSize());
619     }
620     
621     /**
622      * Tests random access reading
623      * <p>
624      * Only executes if the reader implements {@link RandomAccessContent}.
625      */

626     public void testRandomAccessRead() throws Exception JavaDoc
627     {
628         ContentWriter writer = getWriter();
629         // put some content
630
String JavaDoc content = "ABC";
631         byte[] bytes = content.getBytes();
632         writer.putContent(content);
633         ContentReader reader = writer.getReader();
634         
635         FileChannel JavaDoc fileChannel = reader.getFileChannel();
636         assertNotNull("No channel given", fileChannel);
637         
638         // check that no other content access is allowed
639
try
640         {
641             reader.getReadableChannel();
642             fail("Second channel access allowed");
643         }
644         catch (RuntimeException JavaDoc e)
645         {
646             // expected
647
}
648         
649         // read the content
650
ByteBuffer JavaDoc buffer = ByteBuffer.allocate(bytes.length);
651         int count = fileChannel.read(buffer);
652         assertEquals("Incorrect number of bytes read", bytes.length, count);
653         // transfer back to array
654
buffer.rewind();
655         buffer.get(bytes);
656         String JavaDoc checkContent = new String JavaDoc(bytes);
657         assertEquals("Content read failure", content, checkContent);
658         fileChannel.close();
659     }
660 }
661
Popular Tags