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 static java.lang.Boolean.FALSE;
20  import java.lang.reflect.InvocationHandler;
21  import static java.lang.reflect.Proxy.newProxyInstance;
22  import java.util.ArrayList;
23  import java.util.List;
24  
25  import static org.apache.commons.lang.SystemUtils.FILE_SEPARATOR;
26  import static org.apache.commons.lang.SystemUtils.USER_HOME;
27  import org.slf4j.Logger;
28  import static org.slf4j.LoggerFactory.getLogger;
29  
30  import net.sourceforge.domian.entity.Entity;
31  import net.sourceforge.domian.specification.Specification;
32  import net.sourceforge.domian.specification.SpecificationUtils;
33  import net.sourceforge.domian.util.concurrent.locks.Synchronizer;
34  
35  
36  /**
37   * All Domian Core-based {@link net.sourceforge.domian.repository.Repository} classes should extend this abstract class.
38   * It adds partitioning capabilities through the  {@link PartitionRepositoryInvocationHandler} class.
39   * <p/>
40   * A <a href="http://www.slf4j.org">SLF4J</a> logger instance is provided in this class.
41   *
42   * @author Eirik Torske
43   * @since 0.5
44   */
45  public abstract class AbstractDomianCoreRepository<T extends Entity> extends AbstractRepository<T> {
46  // TODO v0.5.1: try
47  //public abstract class AbstractRepository<T extends Entity> extends AbstractSynchronizedObject implements Repository<T> {
48  
49      public static final String DEFAULT_DOMIAN_ROOT_DIR_NAME = ".domian";
50      public static final String DEFAULT_DOMIAN_ROOT_PATH = USER_HOME + FILE_SEPARATOR + DEFAULT_DOMIAN_ROOT_DIR_NAME;
51  
52      protected final Logger log = getLogger(this.getClass());
53  
54      /**
55       * A synchronizer used to control concurrent and exclusive access to repository methods.
56       * E.g. all methods dealing with partitioning are run in an exclusive manner.
57       */
58      protected Synchronizer synchronizer;
59  
60      protected Synchronizer getSynchronizer() {
61          return this.synchronizer;
62      }
63  
64      public void setSynchronizer(final Synchronizer synchronizer) {
65          this.synchronizer = synchronizer;
66      }
67  
68      @Override
69      protected Specification<T> createUniqueSpecificationFor(final T entity) {
70          return SpecificationUtils.createUniqueSpecificationFor(entity);
71      }
72  
73      /*
74      protected Boolean contains(final T entity) {
75          return countAllEntitiesSpecifiedBy(createUniqueSpecificationFor(entity)) > 0;
76      }
77      */
78  
79      /* NB! For this to work, the 'usesNativePartitioningSupport' field must be set in the repository constructor */
80      private InvocationHandler getInvocationHandler() {
81          if (this.usesNativePartitioningSupport) {
82              String repositoryDenomination;
83              if (this instanceof PersistentRepository) {
84                  repositoryDenomination = "'" + ((PersistentRepository) this).getRepositoryId() + "'";
85              } else {
86                  repositoryDenomination = "[repository.hashCode=" + this.hashCode() + "]";
87              }
88              log.info("Repository partition " + repositoryDenomination + " will be using the same repository instance for all sub-partitions having the same repository type '" + this.getClass().getName() + "'");
89              return new PartitionRepositoryReuseInvocationHandler<T>(this);
90  
91          } else {
92              return new PartitionRepositoryInvocationHandler<T>(this, this.synchronizer, FALSE);
93          }
94      }
95  
96      @Override
97      public PartitionRepository<T> makePartition() {
98          final InvocationHandler invocationHandler = getInvocationHandler();
99          final Class[] targetRepositoryInterfaces = getAllRelevantRepositoryInterfaces(this);
100         final Object partitionRepositoryObject = newProxyInstance(AbstractDomianCoreRepository.class.getClassLoader(),
101                                                                   targetRepositoryInterfaces,
102                                                                   invocationHandler);
103         onMakePartition();
104         return (PartitionRepository<T>) partitionRepositoryObject;
105     }
106 
107     @Override
108     protected void onMakePartition() {}
109 
110     private static Class[] getAllRelevantRepositoryInterfaces(final Repository repository) {
111         final List<Class<? extends Repository>> interfaceList = new ArrayList<Class<? extends Repository>>();
112 
113         interfaceList.add(Repository.class);
114         interfaceList.add(PartitionRepository.class);
115 
116         if (repository instanceof VolatileRepository) {
117             interfaceList.add(VolatileRepository.class);
118 
119         } else if (repository instanceof BinaryFormatRepository) {
120             interfaceList.add(PersistentRepository.class);
121             interfaceList.add(BinaryFormatRepository.class);
122 
123         } else if (repository instanceof HumanReadableFormatRepository) {
124             interfaceList.add(PersistentRepository.class);
125             interfaceList.add(TextualFormatRepository.class);
126             interfaceList.add(HumanReadableFormatRepository.class);
127 
128         } else if (repository instanceof TextualFormatRepository) {
129             interfaceList.add(PersistentRepository.class);
130             interfaceList.add(TextualFormatRepository.class);
131 
132         } else if (repository instanceof FakeRepository) {
133             interfaceList.add(FakeRepository.class);
134         }
135         return interfaceList.toArray(new Class[interfaceList.size()]);
136     }
137 }