Gridarta Editor
ValidatorFactory.java
Go to the documentation of this file.
1 /*
2  * Gridarta MMORPG map editor for Crossfire, Daimonin and similar games.
3  * Copyright (C) 2000-2015 The Gridarta Developers.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 package net.sf.gridarta.model.validation.checks;
21 
22 import java.lang.reflect.Constructor;
23 import java.lang.reflect.InvocationTargetException;
24 import java.util.regex.Pattern;
25 import java.util.regex.PatternSyntaxException;
39 import org.jetbrains.annotations.NotNull;
40 
47 public class ValidatorFactory<G extends GameObject<G, A, R>, A extends MapArchObject<A>, R extends Archetype<G, A, R>> {
48 
53  @NotNull
55 
60  @NotNull
62 
67  @NotNull
69 
74  @NotNull
76 
88  public ValidatorFactory(@NotNull final ValidatorPreferences validatorPreferences, @NotNull final GameObjectMatchers gameObjectMatchers, @NotNull final ProjectSettings projectSettings, @NotNull final MapWriter<G, A, R> mapWriter) {
89  this.validatorPreferences = validatorPreferences;
90  this.gameObjectMatchers = gameObjectMatchers;
91  this.projectSettings = projectSettings;
92  this.mapWriter = mapWriter;
93  }
94 
101  @NotNull
102  public Validator<G, A, R> newValidator(@NotNull final CharSequence spec) throws NoSuchValidatorException {
103  final String[] args = StringUtils.PATTERN_WHITESPACE.split(spec);
104  final Class<?> tmpClass;
105  //noinspection ErrorNotRethrown
106  try {
107  tmpClass = Class.forName(args[0]);
108  } catch (final ClassNotFoundException ex) {
109  throw new NoSuchValidatorException("class " + args[0] + " does not exist", ex);
110  } catch (final ExceptionInInitializerError ex) {
111  throw new NoSuchValidatorException("class " + args[0] + " does not exist", ex);
112  } catch (final LinkageError ex) {
113  throw new NoSuchValidatorException("class " + args[0] + " does not exist", ex);
114  }
115  final Class<?> classValidator;
116  try {
117  classValidator = tmpClass.asSubclass(Validator.class);
118  } catch (final ClassCastException ex) {
119  throw new NoSuchValidatorException("class " + args[0] + " does not exist", ex);
120  }
121  final Constructor<?>[] constructors = classValidator.getConstructors();
122  if (constructors.length == 0) {
123  throw new NoSuchValidatorException("class " + args[0] + " has no public constructors");
124  } else if (constructors.length > 1) {
125  throw new NoSuchValidatorException("class " + args[0] + " has more than one public constructor");
126  }
127  //Class.getConstructors() did return the wrong type
128  @SuppressWarnings("unchecked") final Constructor<? extends Validator<G, A, R>> constructor = (Constructor<? extends Validator<G, A, R>>) constructors[0];
129  final Class<?>[] constructorParameterTypes = constructor.getParameterTypes();
130  final Object[] constructorArguments = new Object[constructorParameterTypes.length];
131  int pos = 1;
132  for (int i = 0; i < constructorParameterTypes.length; i++) {
133  final Class<?> constructorParameterType = constructorParameterTypes[i];
134  if (constructorParameterType == ValidatorPreferences.class) {
135  constructorArguments[i] = validatorPreferences;
136  } else if (constructorParameterType == ProjectSettings.class) {
137  constructorArguments[i] = projectSettings;
138  } else if (constructorParameterType == MapWriter.class) {
139  constructorArguments[i] = mapWriter;
140  } else {
141  if (pos >= args.length) {
142  throw new NoSuchValidatorException("missing argument in '" + spec + "'");
143  }
144  final String arg = args[pos++];
145  if (constructorParameterType == Integer[].class) {
146  constructorArguments[i] = createIntegerArray(arg);
147  } else if (constructorParameterType == GameObjectMatcher.class) {
148  constructorArguments[i] = createGameObjectMatcher(arg);
149  } else if (constructorParameterType == int.class) {
150  constructorArguments[i] = createInteger(arg);
151  } else if (constructorParameterType == String[].class) {
152  constructorArguments[i] = createStringArray(args, pos - 1);
153  pos = args.length;
154  } else if (constructorParameterType == Pattern.class) {
155  constructorArguments[i] = createPattern(arg);
156  } else {
157  throw new NoSuchValidatorException("class " + args[0] + "'s constructor requires a parameter of type " + constructorParameterType.getName() + "; this type is not supported");
158  }
159  }
160  }
161  final Validator<G, A, R> validator;
162  //noinspection ErrorNotRethrown
163  try {
164  validator = constructor.newInstance(constructorArguments);
165  } catch (final ExceptionInInitializerError ex) {
166  throw new NoSuchValidatorException("cannot initialize class " + args[0], ex);
167  } catch (final InstantiationException ex) {
168  throw new NoSuchValidatorException("class " + args[0] + " is abstract", ex);
169  } catch (final IllegalAccessException ex) {
170  throw new AssertionError(ex);
171  } catch (final IllegalArgumentException ex) {
172  throw new AssertionError(ex);
173  } catch (final InvocationTargetException ex) {
174  throw new NoSuchValidatorException("cannot instantiate class " + args[0], ex);
175  }
176  if (pos < args.length) {
177  if (classValidator == UnsetSlayingChecker.class) {
178  final UnsetSlayingChecker<?, ?, ?> unsetSlayingChecker = (UnsetSlayingChecker<?, ?, ?>) validator;
179  do {
180  unsetSlayingChecker.addAllowedValue(args[pos]);
181  pos++;
182  } while (pos < args.length);
183  } else if (classValidator == CustomTypeChecker.class) {
184  final CustomTypeChecker<?, ?, ?> customTypeChecker = (CustomTypeChecker<?, ?, ?>) validator;
185  do {
186  final String[] tmp = StringUtils.PATTERN_COMMA.split(args[pos], -1);
187  if (tmp.length != 2 && tmp.length != 3) {
188  throw new NoSuchValidatorException("invalid from,to or from,to,env type: " + args[pos]);
189  }
190  final int fromType;
191  try {
192  fromType = Integer.parseInt(tmp[0]);
193  } catch (final NumberFormatException ex) {
194  throw new NoSuchValidatorException("invalid from type: " + args[pos], ex);
195  }
196  final int toType;
197  try {
198  toType = Integer.parseInt(tmp[1]);
199  } catch (final NumberFormatException ex) {
200  throw new NoSuchValidatorException("invalid to type: " + args[pos], ex);
201  }
202  if (tmp.length == 2) {
203  customTypeChecker.addIgnore(fromType, toType);
204  } else {
205  final int envType;
206  try {
207  envType = Integer.parseInt(tmp[2]);
208  } catch (final NumberFormatException ex) {
209  throw new NoSuchValidatorException("invalid env type: " + args[pos], ex);
210  }
211  customTypeChecker.addIgnore(fromType, toType, envType);
212  }
213  pos++;
214  } while (pos < args.length);
215  } else if (classValidator == SlayingChecker.class) {
216  final SlayingChecker<?, ?, ?> slayingChecker = (SlayingChecker<?, ?, ?>) validator;
217  do {
218  final String[] tmp = StringUtils.PATTERN_COMMA.split(args[pos], 2);
219  if (tmp.length != 2) {
220  throw new NoSuchValidatorException("invalid matcher,pattern: " + args[pos]);
221  }
222  final GameObjectMatcher matcher = createGameObjectMatcher(tmp[0]);
223  final Pattern pattern = createPattern(tmp[1]);
224  slayingChecker.addMatcher(matcher, pattern);
225  pos++;
226  } while (pos < args.length);
227  } else {
228  throw new NoSuchValidatorException("excess arguments for '" + spec + "'");
229  }
230  }
231  return validator;
232  }
233 
241  @NotNull
242  private static Integer[] createIntegerArray(@NotNull final CharSequence arg) throws NoSuchValidatorException {
243  final String[] tmp = StringUtils.PATTERN_COMMA.split(arg, -1);
244  final Integer[] result = new Integer[tmp.length];
245  for (int i = 0; i < tmp.length; i++) {
246  try {
247  result[i] = Integer.parseInt(tmp[i]);
248  } catch (final NumberFormatException ex) {
249  throw new NoSuchValidatorException("not a number: " + tmp[i], ex);
250  }
251  }
252  return result;
253  }
254 
263  @NotNull
264  private String[] createStringArray(@NotNull final String[] args, final int pos) throws NoSuchValidatorException {
265  final StringParameterBuilder stringParameterBuilder = new StringParameterBuilder();
266  stringParameterBuilder.addParameter("COLLECTED", projectSettings.getCollectedDirectory().getPath());
267  stringParameterBuilder.addParameter("ARCH", projectSettings.getArchDirectory().getPath());
268  stringParameterBuilder.addParameter("MAPS", projectSettings.getMapsDirectory().getPath());
269  stringParameterBuilder.addParameter("MAP", MapCheckerScriptChecker.MAP_PLACEHOLDER);
270  stringParameterBuilder.addParameter("REAL_MAP", MapCheckerScriptChecker.REAL_MAP_PLACEHOLDER);
271  final String[] result = new String[args.length - pos];
272  for (int i = 0; i < result.length; i++) {
273  try {
274  result[i] = stringParameterBuilder.replace(args[pos + i]);
275  } catch (final SyntaxErrorException ex) {
276  throw new NoSuchValidatorException(ex.getMessage(), ex);
277  }
278  }
279  return result;
280  }
281 
289  @NotNull
290  private GameObjectMatcher createGameObjectMatcher(@NotNull final String arg) throws NoSuchValidatorException {
291  final GameObjectMatcher gameObjectMatcher = gameObjectMatchers.getMatcher(arg);
292  if (gameObjectMatcher == null) {
293  throw new NoSuchValidatorException("undefined game object matcher: " + arg);
294  }
295  return gameObjectMatcher;
296  }
297 
305  @NotNull
306  private static Integer createInteger(@NotNull final String arg) throws NoSuchValidatorException {
307  try {
308  return Integer.parseInt(arg);
309  } catch (final NumberFormatException ex) {
310  throw new NoSuchValidatorException("invalid number: " + arg, ex);
311  }
312  }
313 
321  @NotNull
322  private static Pattern createPattern(@NotNull final String arg) throws NoSuchValidatorException {
323  try {
324  return Pattern.compile(arg);
325  } catch (final PatternSyntaxException ex) {
326  throw new NoSuchValidatorException("invalid pattern: " + arg, ex);
327  }
328  }
329 
330 }
static Integer createInteger(@NotNull final String arg)
Creates an.
Utility class for string manipulation.
void addIgnore(final int fromType, final int toType)
Adds an allowed type change.
Reading and writing of maps, handling of paths.
Interface for classes that match GameObjects.
This package contains classes related to matching GameObjects, so called GameObjectMatchers.
Settings that apply to a project.
Interface for classes that write map files.
Definition: MapWriter.java:34
This package contains the framework for validating maps.
String replace(@NotNull final CharSequence spec)
Replaces all parameters in a string.
Checks that a game object does not set a custom type.
static final String MAP_PLACEHOLDER
The placeholder in the command&#39;s arguments for the map to check.
final ValidatorPreferences validatorPreferences
The ValidatorPreferences to pass to the newly created Validator instances.
ValidatorFactory(@NotNull final ValidatorPreferences validatorPreferences, @NotNull final GameObjectMatchers gameObjectMatchers, @NotNull final ProjectSettings projectSettings, @NotNull final MapWriter< G, A, R > mapWriter)
Creates a new instance.
An GameObjectValidator to assert that game objects do not have critical slaying strings.
Base package of all Gridarta classes.
Reflects a game object (object on a map).
Definition: GameObject.java:36
void addAllowedValue(@NotNull final String value)
Adds a value which does not trigger a warning.
Validator< G, A, R > newValidator(@NotNull final CharSequence spec)
Creates a new Validator instance from string representation.
final MapWriter< G, A, R > mapWriter
The MapWriter to pass to the newly created Validator instances.
GameObjectMatcher getMatcher(@NotNull final String... ids)
Returns a matcher by id; returns.
Exception thrown if a map validator cannot be created.
String [] createStringArray(@NotNull final String[] args, final int pos)
Creates an.
GameObjects are the objects based on Archetypes found on maps.
Maintains GameObjectMatcher instances.
static Integer [] createIntegerArray(@NotNull final CharSequence arg)
Creates an.
Exception thrown for incorrect arguments.
Checks that a game object does not set a custom type.
Super-interface for validators.
Definition: Validator.java:31
static final Pattern PATTERN_COMMA
The pattern that matches a single comma (",").
static final Pattern PATTERN_WHITESPACE
Pattern to match whitespace excluding NL and CR.
A factory for creating Validator instances from string representation.
static final String REAL_MAP_PLACEHOLDER
The placeholder in the command&#39;s arguments for the real map path.
final ProjectSettings projectSettings
The ProjectSettings to pass to the newly created Validator instances.
File getArchDirectory()
Returns the archetype directory.
File getCollectedDirectory()
Returns the directory where collected archetypes are stored.
GameObjectMatcher createGameObjectMatcher(@NotNull final String arg)
Creates a GameObjectMatcher instance from string representation.
File getMapsDirectory()
Returns the default maps directory.
void addParameter(@NotNull final String key, @NotNull final String value)
Adds a parameter key/value pair.
final GameObjectMatchers gameObjectMatchers
The GameObjectMatchers for looking up GameObjectMatcher instances from string representation.
static Pattern createPattern(@NotNull final String arg)
Creates an.
void addMatcher(@NotNull final GameObjectMatcher gameObjectMatcher, @NotNull final Pattern regex)
Adds a matcher to check.