package pluginbase.config.properties; import pluginbase.config.annotation.Immutable; import pluginbase.config.field.Field; import pluginbase.config.field.FieldInstance; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import pluginbase.config.field.FieldMap; import pluginbase.config.field.FieldMapper; import pluginbase.config.field.PropertyVetoException; import pluginbase.messages.Message; import java.util.Deque; import java.util.LinkedList; import java.util.List; public class PropertiesWrapper implements Properties { private static final transient String SEPARATOR = "."; private static final transient String SEPARATOR_REGEX = "\\."; @Immutable @NotNull private final transient Object object; public static Properties wrapObject(@NotNull Object object) { return new PropertiesWrapper(object); } public static String[] getAllPropertyNames(Class clazz) { return new PropertyNameExtractor(clazz).extractPropertyNames(); } private PropertiesWrapper(@NotNull Object object) { this.object = object; } protected PropertiesWrapper() { this.object = this; } @NotNull @Override public String[] getAllPropertyNames() { return getAllPropertyNames(object.getClass()); } @Nullable @Override public Object getProperty(@NotNull String name) throws NoSuchFieldException { FieldInstance field = getFieldInstance(name); return field.getValue(); } @Override public void setProperty(@NotNull String name, @NotNull String value) throws IllegalAccessException, NoSuchFieldException, PropertyVetoException, IllegalArgumentException { FieldInstance field = getFieldInstanceForModify(name); try { field.getPropertyHandler().set(field, value); } catch (UnsupportedOperationException e) { throw new PropertyVetoException(CANNOT_SET_PROPERTY.bundle(name)); } } @Override public void addProperty(@NotNull String name, @NotNull String value) throws IllegalAccessException, NoSuchFieldException, PropertyVetoException, IllegalArgumentException { FieldInstance field = getFieldInstanceForModify(name); try { field.getPropertyHandler().add(field, value); } catch (UnsupportedOperationException e) { throw new PropertyVetoException(CANNOT_MODIFY_NON_COLLECTION.bundle(name)); } } @Override public void removeProperty(@NotNull String name, @NotNull String value) throws IllegalAccessException, NoSuchFieldException, PropertyVetoException, IllegalArgumentException { FieldInstance field = getFieldInstanceForModify(name); try { field.getPropertyHandler().remove(field, value); } catch (UnsupportedOperationException e) { throw new PropertyVetoException(CANNOT_MODIFY_NON_COLLECTION.bundle(name)); } } @Override public void clearProperty(@NotNull String name, @Nullable String value) throws IllegalAccessException, NoSuchFieldException, PropertyVetoException, IllegalArgumentException { FieldInstance field = getFieldInstanceForModify(name); try { field.getPropertyHandler().clear(field, value); } catch (UnsupportedOperationException e) { throw new PropertyVetoException(CANNOT_MODIFY_NON_COLLECTION.bundle(name)); } } @Nullable @Override public Object getPropertyUnchecked(@NotNull String name) { try { return getProperty(name); } catch (Exception e) { return null; } } @Override public boolean setPropertyUnchecked(@NotNull String name, @NotNull String value) { try { setProperty(name, value); return true; } catch (Exception e) { return false; } } @Override public boolean addPropertyUnchecked(@NotNull String name, @NotNull String value) { try { addProperty(name, value); return true; } catch (Exception e) { return false; } } @Override public boolean removePropertyUnchecked(@NotNull String name, @NotNull String value) { try { removeProperty(name, value); return true; } catch (Exception e) { return false; } } @Override public boolean clearPropertyUnchecked(@NotNull String name, @Nullable String value) { try { clearProperty(name, value); return true; } catch (Exception e) { return false; } } private FieldInstance getFieldInstance(@NotNull String name) throws NoSuchFieldException { String[] path = PropertyAliases.getPropertyName(object.getClass(), name); if (path == null) { path = name.split(SEPARATOR_REGEX); } FieldInstance field = Field.getInstance(object, path); if (field == null) { throw new NoSuchFieldException("No property by that name exists."); } return field; } private FieldInstance getFieldInstanceForModify(@NotNull String name) throws NoSuchFieldException, IllegalAccessException { FieldInstance field = getFieldInstance(name); if (field.isImmutable()) { throw new IllegalAccessException("You may not modify this property."); } return field; } private static class PropertyNameExtractor { Class clazz; List<String> allProperties; Deque<String> currentPropertyParents; PropertyNameExtractor(Class clazz) { this.clazz = clazz; } public String[] extractPropertyNames() { prepareBuffers(); appendNamesFromFieldMap(FieldMapper.getFieldMap(clazz)); return allProperties.toArray(new String[allProperties.size()]); } private void prepareBuffers() { allProperties = new LinkedList<String>(); currentPropertyParents = new LinkedList<String>(); } private void appendNamesFromFieldMap(FieldMap fieldMap) { for (Field field : fieldMap) { String fieldName = field.getName(); if (field.hasChildFields()) { currentPropertyParents.add(fieldName); appendNamesFromFieldMap(field); currentPropertyParents.pollLast(); } else { if (!field.isImmutable()) { appendPropertyName(fieldName); } } } } private void appendPropertyName(String name) { StringBuilder buffer = new StringBuilder(); for (String parent : currentPropertyParents) { buffer.append(parent); buffer.append(SEPARATOR); } buffer.append(name); allProperties.add(buffer.toString()); } } }