View Javadoc

1   /*
2    * Copyright 2006-2010 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package net.sourceforge.domian.repository;
17  
18  
19  import java.util.Collection;
20  import java.util.Iterator;
21  import java.util.concurrent.Callable;
22  
23  import static org.apache.commons.lang.SystemUtils.FILE_SEPARATOR;
24  import org.apache.commons.lang.Validate;
25  import org.apache.commons.lang.NotImplementedException;
26  
27  import net.sourceforge.domian.entity.Entity;
28  import net.sourceforge.domian.repository.HumanReadableFormatRepository;
29  import net.sourceforge.domian.repository.InMemoryRepository;
30  import net.sourceforge.domian.repository.PersistenceDefinition;
31  import static net.sourceforge.domian.repository.PersistenceDefinition.INMEMORY_AND_FILE;
32  import net.sourceforge.domian.specification.Specification;
33  import net.sourceforge.domian.util.concurrent.locks.SemaphoreSynchronizer;
34  import net.sourceforge.domian.util.concurrent.locks.Synchronizer;
35  
36  
37  /**
38   * An in-memory repository with persistence capabilities.
39   * The persistence part is backed by <a href="http://xstream.codehaus.org">XStream</a> functionality.
40   * <p/>
41   * The only persistence definition supported by this repository is {@code PersistenceDefinition.INMEMORY_AND_FILE}.
42   * All entities in this repository are persisted into <i>one single file</i>.
43   * The typical disc footprint is 1KB per entity.
44   * The persistence format is human readable XStream XML.
45   * The file encoding is UTF-8.
46   * <p/>
47   * <i>
48   * File-based stores counts as persistent storage media,
49   * although the nature of the synchronous writings to disc obviously depends on the file system implementations involved.
50   * </i>
51   *
52   * @author Eirik Torske
53   * @see <a href="http://xstream.codehaus.org">XStream</a>
54   * @see <a href="http://domian.sourceforge.net/domian-core/apidocs/net/sourceforge/domian/repository/PersistenceDefinition.html#INMEMORY_AND_FILE"><code>PersistenceDefinition.INMEMORY_AND_FILE</code></a>
55   * @since 0.4
56   */
57  public class InMemoryAndXStreamXmlFileRepository<T extends Entity> extends AbstractXStreamSingleXmlFileRepository<T> implements HumanReadableFormatRepository<T> {
58  
59      protected static final String DEFAULT_REPOSITORY_ROOT_FILE_NAME = "inmemory-and-xstream-xml-file-repository";
60      protected static final String DEFAULT_REPOSITORY_ROOT_DIR_NAME = "." + DEFAULT_REPOSITORY_ROOT_FILE_NAME;
61      protected static final String DEFAULT_REPOSITORY_ROOT_PATH = DEFAULT_DOMIAN_ROOT_PATH + FILE_SEPARATOR + DEFAULT_REPOSITORY_ROOT_DIR_NAME;
62  
63      /** The repository delegate dealing with the in-memory stuff. */
64      protected InMemoryRepository<T> inMemoryRepositoryDelegate;
65  
66      public InMemoryAndXStreamXmlFileRepository(final String repositoryId) {
67          this(DEFAULT_REPOSITORY_ROOT_PATH, repositoryId);
68      }
69  
70      public InMemoryAndXStreamXmlFileRepository(final String repositoryRootPath, final String repositoryId) {
71          this(repositoryRootPath, repositoryId, new SemaphoreSynchronizer());
72      }
73  
74      public InMemoryAndXStreamXmlFileRepository(final String repositoryId, final Synchronizer synchronizer) {
75          this(DEFAULT_REPOSITORY_ROOT_PATH, repositoryId, synchronizer);
76      }
77  
78      public InMemoryAndXStreamXmlFileRepository(final String repositoryRootPath, final String repositoryId, final Synchronizer synchronizer) {
79          Validate.notEmpty(repositoryRootPath, "The repository root path cannot be empty");
80          Validate.notEmpty(repositoryId, "The repository ID cannot be empty");
81          Validate.notNull(synchronizer, "The synchronizer parameter cannot be null");
82          this.repositoryRootPath = repositoryRootPath;
83          this.repositoryId = repositoryId;
84          this.inMemoryRepositoryDelegate = new InMemoryRepository<T>();
85          this.synchronizer = synchronizer;
86          createRepositoryRootPathIfNotExist();
87          //load(); // Hesitant of doing this in constructor, too many side-effects
88      }
89  
90      @Override
91      protected String getRepositoryTypeName() {
92          return DEFAULT_REPOSITORY_ROOT_FILE_NAME;
93      }
94  
95      @Override
96      public <V extends T> Iterator<V> iterateAllEntitiesSpecifiedBy(final Specification<V> specification) {
97          Validate.notNull(specification, "Specification parameter cannot be null");
98          return callConcurrently(new Callable<Iterator<V>>() {
99              @Override
100             public Iterator<V> call() {
101                 return inMemoryRepositoryDelegate.iterateAllEntitiesSpecifiedBy(specification);
102             }
103         });
104     }
105 
106     @Override
107     public <V extends T> Collection<V> findAllEntitiesSpecifiedBy(final Specification<V> specification) {
108         Validate.notNull(specification, "Specification parameter cannot be null");
109         return callConcurrently(new Callable<Collection<V>>() {
110             @Override
111             public Collection<V> call() {
112                 return inMemoryRepositoryDelegate.findAllEntitiesSpecifiedBy(specification);
113             }
114         });
115     }
116 
117     @Override
118     public <V extends T> void put(final V entity) {
119         callConcurrently(new Callable<Void>() {
120             @Override
121             public Void call() {
122                 inMemoryRepositoryDelegate.put(entity);
123                 return null;
124             }
125         });
126     }
127 
128     @Override
129     public <V extends T> void update(V entity) {}
130 
131     @Override
132     public <V extends T> Long removeAllEntitiesSpecifiedBy(final Specification<V> specification) {
133         Validate.notNull(specification, "Specification parameter cannot be null");
134         return callConcurrently(new Callable<Long>() {
135             @Override
136             public Long call() {
137                 return inMemoryRepositoryDelegate.removeAllEntitiesSpecifiedBy(specification);
138             }
139         });
140     }
141 
142     @Override
143     public <V extends T> Boolean remove(final V entity) {
144         return callConcurrently(new Callable<Boolean>() {
145             @Override
146             public Boolean call() {
147                 return inMemoryRepositoryDelegate.remove(entity);
148             }
149         });
150     }
151 
152     @Override
153     public PersistenceDefinition getPersistenceDefinition() {
154         return INMEMORY_AND_FILE;
155     }
156 
157     @Override
158     public String getFormat() {
159         return "XStream XML";
160     }
161 
162     @Override
163     public void load() {
164         callExclusivelyWithRetry(new Load(this));
165     }
166 
167     @Override
168     public void persist() {
169         callExclusivelyWithRetry(new Persist(this));
170     }
171 
172     @Override
173     public void close() {}
174 }