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}