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      }
069
070      /**
071       * Copy constructor.
072       *
073       * @param copyFrom The bean to copy from.
074       */
075      protected Builder(MemoryStore copyFrom) {
076         super(copyFrom);
077         type(copyFrom.getClass());
078      }
079
080      /**
081       * Copy constructor.
082       *
083       * @param copyFrom The builder to copy from.
084       */
085      protected Builder(Builder copyFrom) {
086         super(copyFrom);
087      }
088
089      @Override /* Context.Builder */
090      public Builder copy() {
091         return new Builder(this);
092      }
093
094      @Override /* Context.Builder */
095      public MemoryStore build() {
096         return build(MemoryStore.class);
097      }
098
099      //-----------------------------------------------------------------------------------------------------------------
100      // Properties
101      //-----------------------------------------------------------------------------------------------------------------
102
103      // <FluentSetters>
104
105      @Override /* GENERATED - org.apache.juneau.Context.Builder */
106      public Builder annotations(Annotation...values) {
107         super.annotations(values);
108         return this;
109      }
110
111      @Override /* GENERATED - org.apache.juneau.Context.Builder */
112      public Builder apply(AnnotationWorkList work) {
113         super.apply(work);
114         return this;
115      }
116
117      @Override /* GENERATED - org.apache.juneau.Context.Builder */
118      public Builder applyAnnotations(java.lang.Class<?>...fromClasses) {
119         super.applyAnnotations(fromClasses);
120         return this;
121      }
122
123      @Override /* GENERATED - org.apache.juneau.Context.Builder */
124      public Builder applyAnnotations(Method...fromMethods) {
125         super.applyAnnotations(fromMethods);
126         return this;
127      }
128
129      @Override /* GENERATED - org.apache.juneau.Context.Builder */
130      public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) {
131         super.cache(value);
132         return this;
133      }
134
135      @Override /* GENERATED - org.apache.juneau.Context.Builder */
136      public Builder debug() {
137         super.debug();
138         return this;
139      }
140
141      @Override /* GENERATED - org.apache.juneau.Context.Builder */
142      public Builder debug(boolean value) {
143         super.debug(value);
144         return this;
145      }
146
147      @Override /* GENERATED - org.apache.juneau.Context.Builder */
148      public Builder impl(Context value) {
149         super.impl(value);
150         return this;
151      }
152
153      @Override /* GENERATED - org.apache.juneau.Context.Builder */
154      public Builder type(Class<? extends org.apache.juneau.Context> value) {
155         super.type(value);
156         return this;
157      }
158
159      // </FluentSetters>
160   }
161
162   //-------------------------------------------------------------------------------------------------------------------
163   // Instance
164   //-------------------------------------------------------------------------------------------------------------------
165
166   @Override /* Context */
167   public Builder copy() {
168      return new Builder(this);
169   }
170
171   private final ConcurrentHashMap<String,String> cache = new ConcurrentHashMap<>();
172
173   /**
174    * Constructor.
175    *
176    * @param builder The builder for this object.
177    */
178   public MemoryStore(Builder builder) {
179      super(builder);
180   }
181
182   @Override /* ConfigStore */
183   public synchronized String read(String name) {
184      return emptyIfNull(cache.get(name));
185   }
186
187   @Override /* ConfigStore */
188   public synchronized String write(String name, String expectedContents, String newContents) {
189
190      // This is a no-op.
191      if (eq(expectedContents, newContents))
192         return null;
193
194      String currentContents = read(name);
195
196      if (expectedContents != null && ! eq(currentContents, expectedContents))
197         return currentContents;
198
199      update(name, newContents);
200
201      return null;
202   }
203
204   @Override /* ConfigStore */
205   public synchronized boolean exists(String name) {
206      return cache.containsKey(name);
207   }
208
209   @Override /* ConfigStore */
210   public synchronized MemoryStore update(String name, String newContents) {
211      if (newContents == null)
212         cache.remove(name);
213      else
214         cache.put(name, newContents);
215      super.update(name, newContents);  // Trigger any listeners.
216      return this;
217   }
218
219   /**
220    * No-op.
221    */
222   @Override /* Closeable */
223   public void close() throws IOException {
224      // No-op
225   }
226}