1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package net.sourceforge.domian.repository;
17
18
19 import java.io.File;
20 import java.io.IOException;
21 import static java.lang.Boolean.FALSE;
22 import static java.lang.Boolean.TRUE;
23 import java.util.Collection;
24 import java.util.Date;
25 import java.util.Set;
26 import java.util.concurrent.Callable;
27
28 import static org.apache.commons.io.FileUtils.forceDelete;
29 import static org.apache.commons.io.FileUtils.forceMkdir;
30
31 import net.sourceforge.domian.entity.Entity;
32 import net.sourceforge.domian.repository.EntityPersistenceMetaData;
33 import net.sourceforge.domian.repository.Repository;
34 import static net.sourceforge.domian.specification.SpecificationFactory.allEntities;
35 import net.sourceforge.domian.util.StopWatch;
36
37 import com.thoughtworks.xstream.persistence.FilePersistenceStrategy;
38 import com.thoughtworks.xstream.persistence.PersistenceStrategy;
39 import com.thoughtworks.xstream.persistence.XmlSet;
40
41
42
43
44
45
46
47
48
49 abstract class AbstractXStreamSingleXmlFileRepository<T extends Entity> extends AbstractXStreamXmlFileRepository<T> {
50
51
52 protected abstract String getRepositoryTypeName();
53
54
55
56
57
58 @Override
59 public EntityPersistenceMetaData getMetaDataFor(final T notApplicableEntity) {
60 final PersistenceStrategy metadataPersistenceStrategy =
61 new Type_Id_Date_CustomDenomination_NamedXStreamFilePersistenceStrategy(getRepositoryDirectory(),
62 AbstractXStreamSingleXmlFileRepository.this,
63 "metadata");
64 final Set<Entity[]> metadataXmlSet = new XmlSet(metadataPersistenceStrategy);
65 if (!metadataXmlSet.isEmpty()) {
66 return (EntityPersistenceMetaData) metadataXmlSet.iterator().next()[0];
67 }
68 return null;
69 }
70
71
72
73
74
75 protected void createRepositoryRootPathIfNotExist() {
76 try {
77 forceMkdir(new File(getRepositoryRootPath()));
78 log.info("Repository root '" + getRepositoryRootPath() + "' created (if not already in place...)");
79
80 } catch (IOException e) {
81 log.error("Error when creating repository directory " + getRepositoryRootPath(), e);
82 }
83
84 try {
85 forceMkdir(getRepositoryDirectory());
86 log.info("Repository '" + this.repositoryId + "' created (if not already in place...)");
87
88 } catch (IOException e) {
89 log.error("Error when creating repository directory " + this.repositoryId, e);
90 }
91 }
92
93
94 protected void purgeRepositoryFilesIfExist() {
95 purgeRepositoryFilesIfExist(2, TRUE, TRUE);
96 }
97
98
99 protected void purgeRepositoryEntitiesFileOnly_IfExist() {
100 purgeRepositoryFilesIfExist(1, FALSE, FALSE);
101 }
102
103
104 protected void purgeRepositoryFilesIfExist(final int filesToBePurgedLimit, final Boolean purgeRepositoryFolder, final Boolean purgeMetadata) {
105 int purgedFiles = 0;
106
107 final File repoDirectory = getRepositoryDirectory();
108 if (repoDirectory.exists() && repoDirectory.isDirectory() && repoDirectory.canWrite()) {
109 final File[] files = repoDirectory.listFiles();
110 for (final File file : files) {
111 if (purgedFiles > filesToBePurgedLimit) {
112 throw new IllegalStateException(filesToBePurgedLimit + " files have been deleted in '" + repoDirectory.getAbsolutePath() + "' - revisit test logic and approve behaviour!");
113 }
114 if (!purgeMetadata && file.getName().contains("entities")) {
115 try {
116 log.info("Deleting " + file.getAbsolutePath() + " ...");
117 forceDelete(file);
118 ++purgedFiles;
119
120 } catch (IOException e) {
121 log.error("Error when deleting " + file.getAbsolutePath(), e);
122 }
123 }
124 }
125 if (purgeRepositoryFolder) {
126 try {
127 log.info("Deleting " + repoDirectory.getAbsolutePath() + " ...");
128 forceDelete(repoDirectory);
129
130 } catch (IOException e) {
131 log.error("Error when deleting " + repoDirectory.getAbsolutePath(), e);
132 }
133 }
134 }
135 }
136
137
138
139
140
141 protected class Load implements Callable<Void> {
142 private Repository repository;
143
144 protected Load(final Repository repository) {
145 this.repository = repository;
146 }
147
148 @Override
149 public Void call() throws Exception {
150 StopWatch stopWatch = null;
151 if (log.isInfoEnabled()) {
152 stopWatch = new StopWatch().start();
153 }
154
155
156 final long numberOfEntitiesPurged = this.repository.remove(allEntities());
157 log.info("Repository '" + repositoryId + "': " + numberOfEntitiesPurged + " entities/aggregates purged...");
158
159
160 final PersistenceStrategy persistenceStrategy =
161 new Type_Id_Date_CustomDenomination_NamedXStreamFilePersistenceStrategy(getRepositoryDirectory(),
162 AbstractXStreamSingleXmlFileRepository.this,
163 "entities");
164 final Set<Entity[]> entityXmlSet = new XmlSet(persistenceStrategy);
165 Entity[] persistedEntities = null;
166 if (entityXmlSet != null && !entityXmlSet.isEmpty()) {
167
168 persistedEntities = entityXmlSet.iterator().next();
169 for (final Entity entity : persistedEntities) {
170 this.repository.put(entity);
171 }
172
173 final PersistenceStrategy metadataPersistenceStrategy =
174 new Type_Id_Date_CustomDenomination_NamedXStreamFilePersistenceStrategy(getRepositoryDirectory(),
175 AbstractXStreamSingleXmlFileRepository.this,
176 "metadata");
177 final Set<Entity[]> metadataXmlSet = new XmlSet(metadataPersistenceStrategy);
178 final EntityPersistenceMetaData metadata;
179 if (!metadataXmlSet.isEmpty()) {
180 metadata = (EntityPersistenceMetaData) metadataXmlSet.iterator().next()[0];
181 } else {
182 metadata = new EntityPersistenceMetaData(new Date());
183 }
184 metadataXmlSet.add(new Entity[]{metadata.touchReadMetaData()});
185 }
186 if (log.isInfoEnabled()) {
187 if (persistedEntities != null && persistedEntities.length > 0) {
188 log.info("Repository '" + repositoryId + "' loaded in " + stopWatch.elapsedTimeToString() + " [" + persistedEntities.length + " entities/aggregates in total]");
189 }
190 }
191 return null;
192 }
193 }
194
195
196 protected class Persist implements Callable<Void> {
197 private Repository repository;
198
199 protected Persist(final Repository repository) {
200 this.repository = repository;
201 }
202
203 @Override
204 public Void call() throws Exception {
205 StopWatch stopWatch = null;
206 if (log.isInfoEnabled()) {
207 stopWatch = new StopWatch().start();
208 }
209
210 purgeRepositoryEntitiesFileOnly_IfExist();
211
212
213
214 final Collection<Entity> allEntities = this.repository.find(allEntities());
215 if (!allEntities.isEmpty()) {
216
217
218 final PersistenceStrategy entitiesPersistenceStrategy =
219 new Type_Id_Date_CustomDenomination_NamedXStreamFilePersistenceStrategy(getRepositoryDirectory(),
220 AbstractXStreamSingleXmlFileRepository.this,
221 "entities");
222 final Set<Entity[]> entityXmlSet = new XmlSet(entitiesPersistenceStrategy);
223 entityXmlSet.add(allEntities.toArray(new Entity[allEntities.size()]));
224
225
226 final PersistenceStrategy metadataPersistenceStrategy =
227 new Type_Id_Date_CustomDenomination_NamedXStreamFilePersistenceStrategy(getRepositoryDirectory(),
228 AbstractXStreamSingleXmlFileRepository.this,
229 "metadata");
230 final Set<Entity[]> metadataXmlSet = new XmlSet(metadataPersistenceStrategy);
231 final EntityPersistenceMetaData metadata;
232 if (!metadataXmlSet.isEmpty()) {
233 metadata = (EntityPersistenceMetaData) metadataXmlSet.iterator().next()[0];
234 } else {
235 metadata = new EntityPersistenceMetaData(new Date());
236 }
237 metadataXmlSet.add(new Entity[]{metadata.touchWriteMetaData()});
238 }
239 if (log.isInfoEnabled()) {
240 log.info("Repository '" + repositoryId + "' persisted in " + stopWatch.elapsedTimeToString() + " [" + allEntities.size() + " entities/aggregates in total]");
241 }
242 return null;
243 }
244 }
245
246
247
248 protected class Type_Id_Date_CustomDenomination_NamedXStreamFilePersistenceStrategy extends FilePersistenceStrategy {
249
250 private final AbstractXStreamSingleXmlFileRepository persistentRepository;
251 private final String denomination;
252
253 protected Type_Id_Date_CustomDenomination_NamedXStreamFilePersistenceStrategy(final File repositoryDir,
254 final AbstractXStreamSingleXmlFileRepository persistentRepository,
255 final String denomination) {
256 super(repositoryDir);
257 this.persistentRepository = persistentRepository;
258 this.denomination = denomination;
259 }
260
261 @Override
262 protected boolean isValid(final File dir, final String name) {
263 return name.contains(this.denomination);
264 }
265
266 @Override
267 protected Object extractKey(final String name) {
268 return name;
269 }
270
271 @Override
272 protected String getName(final Object key) {
273 return getRepositoryTypeName() +
274 "_" + this.persistentRepository.getRepositoryId() +
275 "_" + this.denomination +
276 XSTREAM_XML_FILE_SUFFIX;
277 }
278 }
279 }