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