001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.config.store;
014
015import static org.apache.juneau.common.internal.StringUtils.*;
016
017import java.io.*;
018import java.lang.annotation.*;
019import java.lang.reflect.*;
020import java.util.concurrent.*;
021
022import org.apache.juneau.*;
023import org.apache.juneau.internal.*;
024import org.apache.juneau.utils.*;
025
026/**
027 * Filesystem-based storage location for configuration files.
028 *
029 * <p>
030 * Points to a file system directory containing configuration files.
031 *
032 * <h5 class='section'>Notes:</h5><ul>
033 *    <li class='note'>This class is thread safe and reusable.
034 * </ul>
035 */
036public class MemoryStore extends ConfigStore {
037
038   //-------------------------------------------------------------------------------------------------------------------
039   // Static
040   //-------------------------------------------------------------------------------------------------------------------
041
042   /** Default memory store, all default values.*/
043   public static final MemoryStore DEFAULT = MemoryStore.create().build();
044
045   /**
046    * Creates a new builder for this object.
047    *
048    * @return A new builder.
049    */
050   public static Builder create() {
051      return new Builder();
052   }
053
054   //-------------------------------------------------------------------------------------------------------------------
055   // Builder
056   //-------------------------------------------------------------------------------------------------------------------
057
058   /**
059    * Builder class.
060    */
061   @FluentSetters
062   public static class Builder extends ConfigStore.Builder {
063
064      /**
065       * Constructor, default settings.
066       */
067      protected Builder() {
068         super();
069      }
070
071      /**
072       * Copy constructor.
073       *
074       * @param copyFrom The bean to copy from.
075       */
076      protected Builder(MemoryStore copyFrom) {
077         super(copyFrom);
078         type(copyFrom.getClass());
079      }
080
081      /**
082       * Copy constructor.
083       *
084       * @param copyFrom The builder to copy from.
085       */
086      protected Builder(Builder copyFrom) {
087         super(copyFrom);
088      }
089
090      @Override /* Context.Builder */
091      public Builder copy() {
092         return new Builder(this);
093      }
094
095      @Override /* Context.Builder */
096      public MemoryStore build() {
097         return build(MemoryStore.class);
098      }
099
100      //-----------------------------------------------------------------------------------------------------------------
101      // Properties
102      //-----------------------------------------------------------------------------------------------------------------
103
104      // <FluentSetters>
105
106      @Override /* GENERATED - org.apache.juneau.Context.Builder */
107      public Builder annotations(Annotation...values) {
108         super.annotations(values);
109         return this;
110      }
111
112      @Override /* GENERATED - org.apache.juneau.Context.Builder */
113      public Builder apply(AnnotationWorkList work) {
114         super.apply(work);
115         return this;
116      }
117
118      @Override /* GENERATED - org.apache.juneau.Context.Builder */
119      public Builder applyAnnotations(java.lang.Class<?>...fromClasses) {
120         super.applyAnnotations(fromClasses);
121         return this;
122      }
123
124      @Override /* GENERATED - org.apache.juneau.Context.Builder */
125      public Builder applyAnnotations(Method...fromMethods) {
126         super.applyAnnotations(fromMethods);
127         return this;
128      }
129
130      @Override /* GENERATED - org.apache.juneau.Context.Builder */
131      public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) {
132         super.cache(value);
133         return this;
134      }
135
136      @Override /* GENERATED - org.apache.juneau.Context.Builder */
137      public Builder debug() {
138         super.debug();
139         return this;
140      }
141
142      @Override /* GENERATED - org.apache.juneau.Context.Builder */
143      public Builder debug(boolean value) {
144         super.debug(value);
145         return this;
146      }
147
148      @Override /* GENERATED - org.apache.juneau.Context.Builder */
149      public Builder impl(Context value) {
150         super.impl(value);
151         return this;
152      }
153
154      @Override /* GENERATED - org.apache.juneau.Context.Builder */
155      public Builder type(Class<? extends org.apache.juneau.Context> value) {
156         super.type(value);
157         return this;
158      }
159
160      // </FluentSetters>
161   }
162
163   //-------------------------------------------------------------------------------------------------------------------
164   // Instance
165   //-------------------------------------------------------------------------------------------------------------------
166
167   @Override /* Context */
168   public Builder copy() {
169      return new Builder(this);
170   }
171
172   private final ConcurrentHashMap<String,String> cache = new ConcurrentHashMap<>();
173
174   /**
175    * Constructor.
176    *
177    * @param builder The builder for this object.
178    */
179   public MemoryStore(Builder builder) {
180      super(builder);
181   }
182
183   @Override /* ConfigStore */
184   public synchronized String read(String name) {
185      return emptyIfNull(cache.get(name));
186   }
187
188   @Override /* ConfigStore */
189   public synchronized String write(String name, String expectedContents, String newContents) {
190
191      // This is a no-op.
192      if (eq(expectedContents, newContents))
193         return null;
194
195      String currentContents = read(name);
196
197      if (expectedContents != null && ! eq(currentContents, expectedContents))
198         return currentContents;
199
200      update(name, newContents);
201
202      return null;
203   }
204
205   @Override /* ConfigStore */
206   public synchronized boolean exists(String name) {
207      return cache.containsKey(name);
208   }
209
210   @Override /* ConfigStore */
211   public synchronized MemoryStore update(String name, String newContents) {
212      if (newContents == null)
213         cache.remove(name);
214      else
215         cache.put(name, newContents);
216      super.update(name, newContents);  // Trigger any listeners.
217      return this;
218   }
219
220   /**
221    * No-op.
222    */
223   @Override /* Closeable */
224   public void close() throws IOException {
225      // No-op
226   }
227}