001/* 002 * Configurate 003 * Copyright (C) zml and Configurate contributors 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * 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 ninja.leaping.configurate.transformation; 018 019import com.google.common.collect.Iterators; 020import ninja.leaping.configurate.ConfigurationNode; 021import org.checkerframework.checker.nullness.qual.NonNull; 022 023import java.util.Arrays; 024import java.util.Iterator; 025import java.util.SortedMap; 026import java.util.TreeMap; 027 028/** 029 * Represents a set of transformations on a configuration. 030 */ 031public abstract class ConfigurationTransformation { 032 033 /** 034 * A special object that represents a wildcard in a path provided to a configuration transformer 035 */ 036 public static final Object WILDCARD_OBJECT = new Object(); 037 038 /** 039 * Create a new builder to create a basic configuration transformation. 040 * 041 * @return a new transformation builder. 042 */ 043 @NonNull 044 public static Builder builder() { 045 return new Builder(); 046 } 047 048 /** 049 * This creates a builder for versioned transformations. 050 * 051 * @return A new builder for versioned transformations 052 */ 053 @NonNull 054 public static VersionedBuilder versionedBuilder() { 055 return new VersionedBuilder(); 056 } 057 058 /** 059 * Creates a chain of {@link ConfigurationTransformation}s. 060 * 061 * @param transformations The transformations 062 * @return The resultant transformation chain 063 */ 064 @NonNull 065 public static ConfigurationTransformation chain(ConfigurationTransformation... transformations) { 066 return new ChainedConfigurationTransformation(transformations); 067 } 068 069 /** 070 * Apply this transformation to a given node 071 * 072 * @param node The target node 073 */ 074 public abstract void apply(@NonNull ConfigurationNode node); 075 076 /** 077 * Builds a basic {@link ConfigurationTransformation}. 078 */ 079 public static final class Builder { 080 private MoveStrategy strategy = MoveStrategy.OVERWRITE; 081 private final SortedMap<Object[], TransformAction> actions; 082 083 protected Builder() { 084 this.actions = new TreeMap<>(new NodePathComparator()); 085 } 086 087 /** 088 * Adds an action to the transformation. 089 * 090 * @param path The path to apply the action at 091 * @param action The action 092 * @return This builder (for chaining) 093 */ 094 @NonNull 095 public Builder addAction(Object[] path, TransformAction action) { 096 actions.put(path, action); 097 return this; 098 } 099 100 /** 101 * Gets the move strategy to be used by the resultant transformation. 102 * 103 * @return The move strategy 104 */ 105 @NonNull 106 public MoveStrategy getMoveStrategy() { 107 return strategy; 108 } 109 110 /** 111 * Sets the mode strategy to be used by the resultant transformation. 112 * 113 * @param strategy The strategy 114 * @return This builder (for chaining) 115 */ 116 @NonNull 117 public Builder setMoveStrategy(@NonNull MoveStrategy strategy) { 118 this.strategy = strategy; 119 return this; 120 } 121 122 /** 123 * Builds the transformation. 124 * 125 * @return The transformation 126 */ 127 @NonNull 128 public ConfigurationTransformation build() { 129 return new SingleConfigurationTransformation(actions, strategy); 130 } 131 } 132 133 /** 134 * Builds a versioned {@link ConfigurationTransformation}. 135 */ 136 public static final class VersionedBuilder { 137 private Object[] versionKey = new Object[] {"version"}; 138 private final SortedMap<Integer, ConfigurationTransformation> versions = new TreeMap<>(); 139 140 protected VersionedBuilder() {} 141 142 /** 143 * Sets the path of the version key within the configuration. 144 * 145 * @param versionKey The path to the version key 146 * @return This builder (for chaining) 147 */ 148 @NonNull 149 public VersionedBuilder setVersionKey(@NonNull Object... versionKey) { 150 this.versionKey = Arrays.copyOf(versionKey, versionKey.length, Object[].class); 151 return this; 152 } 153 154 /** 155 * Adds a transformation to this builder for the given version. 156 * 157 * @param version The version 158 * @param transformation The transformation 159 * @return This builder (for chaining) 160 */ 161 @NonNull 162 public VersionedBuilder addVersion(int version, @NonNull ConfigurationTransformation transformation) { 163 versions.put(version, transformation); 164 return this; 165 } 166 167 /** 168 * Builds the transformation. 169 * 170 * @return The transformation 171 */ 172 @NonNull 173 public ConfigurationTransformation build() { 174 return new VersionedTransformation(versionKey, versions); 175 } 176 } 177 178 /** 179 * Implementation of {@link ninja.leaping.configurate.transformation.NodePath} used by this class. 180 */ 181 // TODO Remove usages of this class in favour of the NodePath interface (breaking change for 4.0) 182 public static final class NodePath implements ninja.leaping.configurate.transformation.NodePath { 183 Object[] arr; 184 185 NodePath() { 186 } 187 188 @Override 189 public Object get(int i) { 190 return arr[i]; 191 } 192 193 @Override 194 public int size() { 195 return arr.length; 196 } 197 198 @Override 199 public Object[] getArray() { 200 return Arrays.copyOf(arr, arr.length); 201 } 202 203 @NonNull 204 @Override 205 public Iterator<Object> iterator() { 206 return Iterators.forArray(arr); 207 } 208 } 209}