Added a better and more complete implementation for attributes with sane class names.

This commit is contained in:
sk89q 2013-02-07 12:11:25 -08:00
parent a0dceaa713
commit ee2ed762c2
14 changed files with 546 additions and 65 deletions

View File

@ -23,6 +23,7 @@ import java.util.Map;
import org.apache.commons.lang.Validate;
import com.sk89q.worldguard.region.attribute.Attribute;
import com.sk89q.worldguard.region.shapes.IndexableShape;
/**

View File

@ -16,7 +16,7 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.region;
package com.sk89q.worldguard.region.attribute;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@ -24,6 +24,8 @@ import java.io.IOException;
import org.apache.commons.lang.Validate;
import com.sk89q.worldguard.region.Region;
/**
* Attributes can be attached to regions to store all sorts of data.
* <p>
@ -36,16 +38,16 @@ import org.apache.commons.lang.Validate;
* </ul>
* <p>
* Asking for attributes from a region will return a subclass of
* this class, which can be either an instance of {@link DataValuedAttribute}
* this class, which can be either an instance of {@link ByteArray}
* or a custom overriding attribute class available in WorldGuard or
* from another project.
* <p>
* Creating your attributes to store any type of data is easy. The most
* important decision to make is whether to use {@link DataValuedAttribute}
* important decision to make is whether to use {@link ByteArray}
* or your own subclass. The latter lets you store the attribute data
* in a structure more native to your software (using primitive data types and
* your own objects), but it may be not be necessary if your payload does
* consist of raw binary data, which is what {@link DataValuedAttribute} does.
* consist of raw binary data, which is what {@link ByteArray} does.
* <p>
* When you make a subclass, you must define the
* {@link #read(DataInputStream, int)} and
@ -62,7 +64,7 @@ import org.apache.commons.lang.Validate;
* the classpath, as the canonical name of each attribute's class is saved
* during saving. The process involved here is outlined more closely on
* the WorldGuard wiki. If worse comes to worse, and the subclass cannot
* be found, then the data will be loaded as an {@link DataValuedAttribute},
* be found, then the data will be loaded as an {@link ByteArray},
* which prevents loss of the raw binary data, but it will render the
* data unusuable during runtime unless explicitly deserialization is
* conducted when recalling the attribute.
@ -72,9 +74,10 @@ public abstract class Attribute {
private String name = "unnamed";
/**
* A no-arg constructor required for automatic instantiation of
* attributes. If you are overriding this class, you must provide
* this constructor.
* A constructor required for automatic instantiation of attributes.
* <p>
* If you are overriding this class, you must provide this constructor.
* Be aware that the default name of attributes is 'unnamed'.
*/
public Attribute() {
}
@ -134,7 +137,7 @@ public abstract class Attribute {
* @param len length of the data
* @throw IOException thrown on read error, which would cause the instance
* of this class to fail, causing the region index to
* fall back to {@link DataValuedAttribute}
* fall back to {@link ByteArray}
*/
public abstract void read(DataInputStream in, int len) throws IOException;

View File

@ -16,7 +16,7 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.region;
package com.sk89q.worldguard.region.attribute;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@ -25,32 +25,31 @@ import java.io.IOException;
import org.apache.commons.lang.Validate;
/**
* A simple implementation of {@link Attribute} that saves the raw binary
* data stream for exact recall later during runtime and during serialization.
* Stores raw byte array data.
* <p>
* By itself, this class will accept binary data, store it as-is, then
* dump it back out as binary data when requested. If you have special needs,
* and do not want to have to explicitly deserialize the contents contained
* within this attribute, consider subclassing {@link Attribute} instead.
* <p>
* This is the automatic fallback attribute in case custom attribute
* classes are unavailable during load.
* If no more accurate {@link Attribute} class is found during deserialization,
* this class is used because it would maintain the data. If you wish to create
* your own {@link Attribute}s, consider subclassing that class rather than
* using this class.
*
* @see Managed another way to store byte arrays (with more memory cost and null
* support)
*/
public final class DataValuedAttribute extends Attribute {
public final class ByteArray extends Attribute {
private byte[] buffer;
private byte[] value;
/**
* Construct the attribute with a default name.
*/
public DataValuedAttribute() {
public ByteArray() {
super();
}
/**
* Construct the attribute with a given name.
*/
public DataValuedAttribute(String name) {
public ByteArray(String name) {
super(name);
}
@ -62,23 +61,21 @@ public final class DataValuedAttribute extends Attribute {
*
* @return data
*/
public byte[] getByteArray() {
return buffer;
public byte[] getValue() {
return value;
}
/**
* Set the raw byte array.
* <p>
* The given byte array is not copied and so further modifications to the
* given byte array will have the changes reflect on the byte array
* inside this object.
* The given byte array is stored as a reference within this instance.
*
* @param data new data
*/
public void setByteArray(byte[] data) {
Validate.notNull(data);
public void setValue(byte[] value) {
Validate.notNull(value);
this.buffer = data;
this.value = value;
}
/**
@ -87,19 +84,19 @@ public final class DataValuedAttribute extends Attribute {
* @return length in bytes of data
*/
public int size() {
return buffer.length;
return value.length;
}
@Override
public void read(DataInputStream in, int len) throws IOException {
byte[] buffer = new byte[len];
in.read(buffer, 0, len);
this.buffer = buffer;
this.value = buffer;
}
@Override
public void write(DataOutputStream out) throws IOException {
out.write(buffer);
out.write(value);
}
}

View File

@ -0,0 +1,85 @@
// $Id$
/*
* This file is a part of WorldGuard.
* Copyright (c) sk89q <http://www.sk89q.com>
* Copyright (c) the WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY), without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.region.attribute;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* An attribute that stores two states (booleans).
*
* @see Managed another way to store booleans (with more memory cost and null
* support)
*/
public class Flag extends Attribute {
private boolean value;
/**
* Construct an instance and assign a default name.
*
* @see Attribute#Attribute() for basic mechanics
*/
public Flag() {
}
/**
* Construct an instance and specify an attribute name.
*
* @param name name of the attribute
*/
public Flag(String name) {
super(name);
}
/**
* Get the value.
*
* @return the value
*/
public boolean getValue() {
return value;
}
/**
* Set the value.
*
* @param value the new value
*/
public void setValue(boolean value) {
this.value = value;
}
@Override
public void read(DataInputStream in, int len) throws IOException {
value = in.readBoolean();
}
@Override
public void write(DataOutputStream out) throws IOException {
out.writeBoolean(value);
}
@Override
public String toString() {
return String.valueOf(value);
}
}

View File

@ -16,25 +16,28 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.region;
package com.sk89q.worldguard.region.attribute;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import org.apache.commons.lang.Validate;
/**
* An attribute that stores string data.
* An attribute that stores doubles.
*
* @see Managed another way to store numbers (with more memory cost and null
* support)
*/
public class StringAttr extends Attribute {
public class Fraction extends Attribute {
private String data;
private double value;
/**
* No-arg constructor.
* Construct an instance and assign a default name.
*
* @see Attribute#Attribute() for basic mechanics
*/
public StringAttr() {
public Fraction() {
}
/**
@ -42,43 +45,41 @@ public class StringAttr extends Attribute {
*
* @param name name of the attribute
*/
public StringAttr(String name) {
public Fraction(String name) {
super(name);
}
/**
* Get the text.
* Get the value.
*
* @return the text
* @return the value
*/
public String getText() {
return data;
public double getValue() {
return value;
}
/**
* Set the stored text.
* Set the value.
*
* @param text the new text
* @param value the new value
*/
public void setText(String text) {
Validate.notNull(text);
this.data = text;
public void setValue(double value) {
this.value = value;
}
@Override
public void read(DataInputStream in, int len) throws IOException {
data = in.readUTF();
value = in.readDouble();
}
@Override
public void write(DataOutputStream out) throws IOException {
out.writeUTF(data);
out.writeDouble(value);
}
@Override
public String toString() {
return data;
return String.valueOf(value);
}
}

View File

@ -0,0 +1,96 @@
// $Id$
/*
* This file is a part of WorldGuard.
* Copyright (c) sk89q <http://www.sk89q.com>
* Copyright (c) the WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY), without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.region.attribute;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* An attribute that serializes and de-serializes objects automatically
* using Java's serialization methods.
* <p>
* This class allows for null values.
*/
public class Managed<T> extends Attribute {
private T value;
/**
* Construct an instance and assign a default name.
*
* @see Attribute#Attribute() for basic mechanics
*/
public Managed() {
}
/**
* Construct an instance and specify an attribute name.
*
* @param name name of the attribute
*/
public Managed(String name) {
super(name);
}
/**
* Get the value.
*
* @return the value or null
*/
public T getValue() {
return value;
}
/**
* Set the value.
*
* @param value the new value or null
*/
public void setValue(T value) {
this.value = value;
}
@SuppressWarnings("unchecked")
@Override
public void read(DataInputStream in, int len) throws IOException {
ObjectInputStream objIn = new ObjectInputStream(in);
try {
value = (T) objIn.readObject();
} catch (ClassCastException e) {
throw new IOException("Deserialized object was something else", e);
} catch (ClassNotFoundException e) {
throw new IOException("Deserialized object uses class not found", e);
}
}
@Override
public void write(DataOutputStream out) throws IOException {
ObjectOutputStream objOut = new ObjectOutputStream(out);
objOut.writeObject(out);
}
@Override
public String toString() {
return String.valueOf(value);
}
}

View File

@ -0,0 +1,93 @@
// $Id$
/*
* This file is a part of WorldGuard.
* Copyright (c) sk89q <http://www.sk89q.com>
* Copyright (c) the WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY), without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.region.attribute;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import org.apache.commons.lang.Validate;
/**
* An attribute that stores strings.
* <p>
* Compared to {@link Managed}, strings stored with this class use less
* space and memory. Be aware that strings stored with this class
* are limited to the size of an unsigned short.
*
* @see Managed another way to store strings (with more memory cost and null
* support)
*/
public class Message extends Attribute {
private String value = "";
/**
* Construct an instance and assign a default name.
*
* @see Attribute#Attribute() for basic mechanics
*/
public Message() {
}
/**
* Construct an instance and specify an attribute name.
*
* @param name name of the attribute
*/
public Message(String name) {
super(name);
}
/**
* Get the value.
*
* @return the value
*/
public String getValue() {
return value;
}
/**
* Set the value.
*
* @param value the new value (cannot be null)
*/
public void setValue(String value) {
Validate.notNull(value);
this.value = value;
}
@Override
public void read(DataInputStream in, int len) throws IOException {
value = in.readUTF();
}
@Override
public void write(DataOutputStream out) throws IOException {
out.writeUTF(value);
}
@Override
public String toString() {
return String.valueOf(value);
}
}

View File

@ -0,0 +1,86 @@
// $Id$
/*
* This file is a part of WorldGuard.
* Copyright (c) sk89q <http://www.sk89q.com>
* Copyright (c) the WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY), without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.region.attribute;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* An attribute that stores whole numbers (integers) with a range of
* {@link Integer#MIN_VALUE} to {@link Integer#MAX_VALUE}.
*
* @see Managed another way to store numbers (with more memory cost and null
* support)
*/
public class Number extends Attribute {
private int value;
/**
* Construct an instance and assign a default name.
*
* @see Attribute#Attribute() for basic mechanics
*/
public Number() {
}
/**
* Construct an instance and specify an attribute name.
*
* @param name name of the attribute
*/
public Number(String name) {
super(name);
}
/**
* Get the value.
*
* @return the value
*/
public int getValue() {
return value;
}
/**
* Set the value.
*
* @param value the new value
*/
public void setValue(int value) {
this.value = value;
}
@Override
public void read(DataInputStream in, int len) throws IOException {
value = in.readInt();
}
@Override
public void write(DataOutputStream out) throws IOException {
out.write(value);
}
@Override
public String toString() {
return String.valueOf(value);
}
}

View File

@ -0,0 +1,111 @@
// $Id$
/*
* This file is a part of WorldGuard.
* Copyright (c) sk89q <http://www.sk89q.com>
* Copyright (c) the WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY), without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.region.attribute;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import org.apache.commons.lang.Validate;
/**
* An attribute that stores three states (none, allow, and deny).
*
* @see Managed another way to store booleans (with more memory cost and null
* support)
*/
public class State extends Attribute {
public static enum Type {
NONE,
ALLOW,
DENY
}
private Type value = Type.NONE;
/**
* Construct an instance and assign a default name.
*
* @see Attribute#Attribute() for basic mechanics
*/
public State() {
}
/**
* Construct an instance and specify an attribute name.
*
* @param name name of the attribute
*/
public State(String name) {
super(name);
}
/**
* Get the value.
*
* @return the value
*/
public Type getValue() {
return value;
}
/**
* Set the value.
*
* @param value the new value
*/
public void setValue(Type value) {
Validate.notNull(value);
this.value = value;
}
/**
* Returns whether the value is {@link Type#NONE} or {@link Type#ALLOW}.
*
* @return whether the value is for allow
*/
public boolean allows() {
return value == Type.NONE || value == Type.ALLOW;
}
@Override
public void read(DataInputStream in, int len) throws IOException {
int ordinal = in.readByte();
Type[] values = Type.values();
if (ordinal < 0 || ordinal >= values.length) {
value = Type.NONE;
} else {
value = values[ordinal];
}
}
@Override
public void write(DataOutputStream out) throws IOException {
out.writeByte(value.ordinal());
}
@Override
public String toString() {
return String.valueOf(value);
}
}

View File

@ -16,7 +16,7 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldguard.region;
package com.sk89q.worldguard.region.attribute;
import java.io.DataInputStream;
import java.io.DataOutputStream;

View File

@ -44,8 +44,6 @@ import com.sk89q.rebar.util.LoggerUtils;
import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldguard.region.Region;
import com.sk89q.worldguard.region.flags.DefaultFlag;
import com.sk89q.worldguard.region.flags.Flag;
import com.sk89q.worldguard.region.indices.RegionIndex;
import com.sk89q.worldguard.region.indices.RegionIndexFactory;
import com.sk89q.worldguard.region.shapes.Cuboid;
@ -166,7 +164,8 @@ public class YamlStore implements RegionStore {
Region region = new Region(id, shape);
region.setPriority(node.getInt("priority", 0));
loadFlags(region, node.getNode("flags"));
loadFlags(region, node.getNode("flags")); // Legacy flags support
loadAttributes(region, node.getNode("attr"));
// Remember the parent so that it can be linked lateron
String parentId = node.getString("parent");
@ -272,6 +271,9 @@ public class YamlStore implements RegionStore {
}
}
}
private void loadAttributes(Region region, ConfigurationNode node) {
}
/**
* Try to set a flag on a region from its raw value. The flag will be properly

View File

@ -28,6 +28,8 @@ import java.io.IOException;
import org.junit.Test;
import com.sk89q.worldguard.region.attribute.Attribute;
public class AttributeTest {
private Attribute makeAttribute(String name) {

View File

@ -28,15 +28,17 @@ import java.io.IOException;
import org.junit.Test;
import com.sk89q.worldguard.region.attribute.ByteArray;
public class DataValuedAttributeTest extends AttributeTest {
private DataValuedAttribute makeAttribute(String name) {
return new DataValuedAttribute(name);
private ByteArray makeAttribute(String name) {
return new ByteArray(name);
}
@Test
public void testRead() throws IOException {
DataValuedAttribute attribute = makeAttribute("testing");
ByteArray attribute = makeAttribute("testing");
byte[] data = new byte[] { 1, 2, 3, 4, 5, 6 };
attribute.read(new DataInputStream(new ByteArrayInputStream(data)), data.length);
assertArrayEquals(data, attribute.getByteArray());
@ -45,8 +47,8 @@ public class DataValuedAttributeTest extends AttributeTest {
@Test
public void testWrite() throws IOException {
byte[] data = new byte[] { 1, 2, 3, 4, 5, 6 };
DataValuedAttribute attribute = makeAttribute("testing");
attribute.setByteArray(data);
ByteArray attribute = makeAttribute("testing");
attribute.setValue(data);
ByteArrayOutputStream stream = new ByteArrayOutputStream(100);
attribute.write(new DataOutputStream(stream));

View File

@ -24,6 +24,8 @@ import java.io.IOException;
import org.junit.Ignore;
import com.sk89q.worldguard.region.attribute.Attribute;
@Ignore
public class TestAttribute extends Attribute {