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.commons.utils.Shorts.*;
020import static org.apache.juneau.commons.utils.StringUtils.*;
021
022import java.io.*;
023import java.util.concurrent.*;
024
025/**
026 * Filesystem-based storage location for configuration files.
027 *
028 * <p>
029 * Points to a file system directory containing configuration files.
030 *
031 * <h5 class='section'>Notes:</h5><ul>
032 *    <li class='note'>This class is thread safe and reusable.
033 * </ul>
034 */
035@SuppressWarnings({
036   "java:S1192", // Duplicated literals (argument/property names) read more clearly inline than as constants
037   "resource" // Resource management handled externally
038})
039public class MemoryStore extends ConfigStore {
040
041   /**
042    * Builder class.
043    */
044   public static class Builder extends ConfigStore.Builder<Builder> {
045
046      /**
047       * Constructor, default settings.
048       */
049      protected Builder() {}
050
051      /**
052       * Copy constructor.
053       *
054       * @param copyFrom The builder to copy from.
055       *    <br>Cannot be <jk>null</jk>.
056       */
057      protected Builder(Builder copyFrom) {
058         super(reqnn("copyFrom", copyFrom));
059      }
060
061      /**
062       * Copy constructor.
063       *
064       * @param copyFrom The bean to copy from.
065       *    <br>Cannot be <jk>null</jk>.
066       */
067      protected Builder(MemoryStore copyFrom) {
068         super(reqnn("copyFrom", copyFrom));
069         type(copyFrom.getClass());
070      }
071
072      @Override /* Overridden from Context.Builder<?> */
073      public MemoryStore build() {
074         return build(MemoryStore.class);
075      }
076
077      @Override /* Overridden from Context.Builder<?> */
078      public Builder copy() {
079         return new Builder(this);
080      }
081
082   }
083
084   /** Default memory store, all default values.*/
085   public static final MemoryStore DEFAULT = MemoryStore.create().build();
086
087   /**
088    * Creates a new builder for this object.
089    *
090    * @return A new builder.
091    */
092   public static Builder create() {
093      return new Builder();
094   }
095
096   private final ConcurrentHashMap<String,String> cache = new ConcurrentHashMap<>();
097
098   /**
099    * Constructor.
100    *
101    * @param builder The builder for this object.
102    *    <br>Cannot be <jk>null</jk>.
103    */
104   public MemoryStore(Builder builder) {
105      super(builder);
106   }
107
108   /**
109    * No-op.
110    */
111   @Override /* Overridden from Closeable */
112   public void close() throws IOException {
113      // No-op
114   }
115
116   @Override /* Overridden from Context */
117   public Builder copy() {
118      return new Builder(this);
119   }
120
121   @Override /* Overridden from ConfigStore */
122   public synchronized boolean exists(String name) {
123      return cache.containsKey(name);
124   }
125
126   @Override /* Overridden from ConfigStore */
127   public synchronized String read(String name) {
128      return emptyIfNull(cache.get(name));
129   }
130
131   @Override /* Overridden from ConfigStore */
132   public synchronized MemoryStore update(String name, String newContents) {
133      if (newContents == null)
134         cache.remove(name);
135      else
136         cache.put(name, newContents);
137      super.update(name, newContents);  // Trigger any listeners.
138      return this;
139   }
140
141   @Override /* Overridden from ConfigStore */
142   public synchronized String write(String name, String expectedContents, String newContents) {
143
144      // This is a no-op.
145      if (eq(expectedContents, newContents))
146         return null;
147
148      var currentContents = read(name);
149
150      if (nn(expectedContents) && neq(currentContents, expectedContents))
151         return currentContents;
152
153      update(name, newContents);
154
155      return null;
156   }
157}