Index: src/tests/antunit/core/ant-attribute-test.xml
===================================================================
--- src/tests/antunit/core/ant-attribute-test.xml (revision 0)
+++ src/tests/antunit/core/ant-attribute-test.xml (revision 0)
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: src/main/org/apache/tools/ant/ComponentHelper.java
===================================================================
--- src/main/org/apache/tools/ant/ComponentHelper.java (revision 574890)
+++ src/main/org/apache/tools/ant/ComponentHelper.java (working copy)
@@ -289,6 +289,7 @@
public void initDefaultDefinitions() {
initTasks();
initTypes();
+ new DefaultDefinitions(this).execute();
}
/**
Index: src/main/org/apache/tools/ant/UnknownElement.java
===================================================================
--- src/main/org/apache/tools/ant/UnknownElement.java (revision 574890)
+++ src/main/org/apache/tools/ant/UnknownElement.java (working copy)
@@ -167,6 +167,9 @@
*
*/
public void configure(Object realObject) {
+ if (realObject == null) {
+ return;
+ }
realThing = realObject;
getWrapper().setProxy(realThing);
@@ -278,10 +281,8 @@
*/
public void execute() {
if (realThing == null) {
- // plain impossible to get here, maybeConfigure should
- // have thrown an exception.
- throw new BuildException("Could not create task of type: "
- + elementName, getLocation());
+ // Got here if the runtimeconfigurable is not enabled.
+ return;
}
try {
if (realThing instanceof Task) {
@@ -340,6 +341,14 @@
RuntimeConfigurable childWrapper = parentWrapper.getChild(i);
UnknownElement child = (UnknownElement) it.next();
try {
+ if (!childWrapper.isEnabled(child)) {
+ if (ih.supportsNestedElement(
+ parentUri, ProjectHelper.genComponentName(
+ child.getNamespace(), child.getTag()))) {
+ continue;
+ }
+ // fall tru and fail in handlechild (unsupported element)
+ }
if (!handleChild(
parentUri, ih, parent, child, childWrapper)) {
if (!(parent instanceof TaskContainer)) {
@@ -405,6 +414,9 @@
* @return the task or data type represented by the given unknown element.
*/
protected Object makeObject(UnknownElement ue, RuntimeConfigurable w) {
+ if (!w.isEnabled(ue)) {
+ return null;
+ }
ComponentHelper helper = ComponentHelper.getComponentHelper(
getProject());
String name = ue.getComponentName();
Index: src/main/org/apache/tools/ant/DefaultDefinitions.java
===================================================================
--- src/main/org/apache/tools/ant/DefaultDefinitions.java (revision 0)
+++ src/main/org/apache/tools/ant/DefaultDefinitions.java (revision 0)
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+/**
+ * Default definitions.
+ */
+public final class DefaultDefinitions {
+ private static final String IF_NAMESPACE = "ant:if";
+ private static final String UNLESS_NAMESPACE = "ant:unless";
+ private static final String OATA = "org.apache.tools.ant.";
+
+ private final ComponentHelper componentHelper;
+
+ /**
+ * Create a default definitions object.
+ * @param componentHelper the componenthelper to initialize.
+ */
+ public DefaultDefinitions(ComponentHelper componentHelper) {
+ this.componentHelper = componentHelper;
+ }
+
+ /**
+ * Register the defintions.
+ */
+ public void execute() {
+ attributeNamespaceDef(IF_NAMESPACE);
+ attributeNamespaceDef(UNLESS_NAMESPACE);
+
+ ifUnlessDef("true", "IfTrueAttribute");
+ ifUnlessDef("set", "IfSetAttribute");
+ ifUnlessDef("blank", "IfBlankAttribute");
+ }
+
+ private void attributeNamespaceDef(String ns) {
+ AntTypeDefinition def = new AntTypeDefinition();
+ def.setName(ProjectHelper.nsToComponentName(ns));
+ def.setClassName(OATA + "attribute.AttributeNamespace");
+ def.setClassLoader(getClass().getClassLoader());
+ def.setRestrict(true);
+ componentHelper.addDataTypeDefinition(def);
+ }
+
+ private void ifUnlessDef(String name, String base) {
+ String classname = OATA + "attribute." + base;
+ componentDef(IF_NAMESPACE, name, classname);
+ componentDef(UNLESS_NAMESPACE, name, classname + "$Unless");
+ }
+
+ private void componentDef(String ns, String name, String classname) {
+ AntTypeDefinition def = new AntTypeDefinition();
+ String n = ProjectHelper.genComponentName(ns, name);
+ def.setName(ProjectHelper.genComponentName(ns, name));
+ def.setClassName(classname);
+ def.setClassLoader(getClass().getClassLoader());
+ def.setRestrict(true);
+ componentHelper.addDataTypeDefinition(def);
+ }
+}
Index: src/main/org/apache/tools/ant/attribute/AttributeNamespace.java
===================================================================
--- src/main/org/apache/tools/ant/attribute/AttributeNamespace.java (revision 0)
+++ src/main/org/apache/tools/ant/attribute/AttributeNamespace.java (revision 0)
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.attribute;
+
+/**
+ * This class is used to indicate that the xml namespace (uri)
+ * can be used to look for namespace attributes.
+ */
+public final class AttributeNamespace {
+}
Index: src/main/org/apache/tools/ant/attribute/IfTrueAttribute.java
===================================================================
--- src/main/org/apache/tools/ant/attribute/IfTrueAttribute.java (revision 0)
+++ src/main/org/apache/tools/ant/attribute/IfTrueAttribute.java (revision 0)
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.attribute;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.UnknownElement;
+
+/**
+ * Check if an attribute value is true or not.
+ */
+public class IfTrueAttribute extends BaseIfAttribute {
+ /** The unless version */
+ public static class Unless extends IfTrueAttribute {
+ { setPositive(false); }
+ }
+
+ /**
+ * check if the attribute value is true or not
+ * {@inheritDoc}
+ */
+ public boolean isEnabled(UnknownElement el, String value) {
+ return convertResult(Project.toBoolean(value));
+ }
+}
Index: src/main/org/apache/tools/ant/attribute/EnableAttribute.java
===================================================================
--- src/main/org/apache/tools/ant/attribute/EnableAttribute.java (revision 0)
+++ src/main/org/apache/tools/ant/attribute/EnableAttribute.java (revision 0)
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.attribute;
+
+import org.apache.tools.ant.UnknownElement;
+
+/**
+ * This interface is used by ant attributes.
+ */
+public interface EnableAttribute {
+ /**
+ * is enabled.
+ * @param el the unknown element this attribute is in.
+ * @param value the value of the attribute.
+ * @return true if the attribute enables the element, false otherwise.
+ */
+ boolean isEnabled(UnknownElement el, String value);
+}
Index: src/main/org/apache/tools/ant/attribute/IfBlankAttribute.java
===================================================================
--- src/main/org/apache/tools/ant/attribute/IfBlankAttribute.java (revision 0)
+++ src/main/org/apache/tools/ant/attribute/IfBlankAttribute.java (revision 0)
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.attribute;
+
+import org.apache.tools.ant.UnknownElement;
+
+/**
+ * Check if an attribute is blank or not.
+ */
+public class IfBlankAttribute extends BaseIfAttribute {
+ /** The unless version */
+ public static class Unless extends IfBlankAttribute {
+ { setPositive(false); }
+ }
+ /**
+ * check if the attribute value is blank or not
+ * {@inheritDoc}
+ */
+ public boolean isEnabled(UnknownElement el, String value) {
+ return convertResult((value == null || "".equals(value)));
+ }
+}
Index: src/main/org/apache/tools/ant/attribute/BaseIfAttribute.java
===================================================================
--- src/main/org/apache/tools/ant/attribute/BaseIfAttribute.java (revision 0)
+++ src/main/org/apache/tools/ant/attribute/BaseIfAttribute.java (revision 0)
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.attribute;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.RuntimeConfigurable;
+import org.apache.tools.ant.UnknownElement;
+
+
+/**
+ * An abstract class for if/unless attributes.
+ * This contains a boolean flag to specify whether this is an
+ * if or unless attribute.
+ */
+public abstract class BaseIfAttribute
+ extends ProjectComponent implements EnableAttribute {
+ private boolean positive = true;
+ /**
+ * Set the positive flag.
+ * @param positive the value to use.
+ */
+ protected void setPositive(boolean positive) {
+ this.positive = positive;
+ }
+
+ /**
+ * Get the positive flag.
+ * @return the flag.
+ */
+ protected boolean isPositive() {
+ return positive;
+ }
+
+ /**
+ * convert the result.
+ * @param val the result to convert
+ * @return val if positive or !val if not.
+ */
+ protected boolean convertResult(boolean val) {
+ return positive ? val : !val;
+ }
+
+ /**
+ * Get all the attributes in the ant-attribute:param
+ * namespace and place them in a map.
+ * @param el the element this attribute is in.
+ * @return a map of attributes.
+ */
+ protected Map getParams(UnknownElement el) {
+ Map ret = new HashMap();
+ RuntimeConfigurable rc = el.getWrapper();
+ Map attributes = rc.getAttributeMap(); // This does a copy!
+ for (Iterator i = attributes.entrySet().iterator(); i.hasNext();) {
+ Map.Entry entry = (Map.Entry) i.next();
+ String key = (String) entry.getKey();
+ String value = (String) entry.getValue();
+ if (key.startsWith("ant-attribute:param")) {
+ int pos = key.lastIndexOf(':');
+ ret.put(key.substring(pos + 1),
+ el.getProject().replaceProperties(value));
+ }
+ }
+ return ret;
+ }
+}
Index: src/main/org/apache/tools/ant/attribute/IfSetAttribute.java
===================================================================
--- src/main/org/apache/tools/ant/attribute/IfSetAttribute.java (revision 0)
+++ src/main/org/apache/tools/ant/attribute/IfSetAttribute.java (revision 0)
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.attribute;
+
+import org.apache.tools.ant.UnknownElement;
+
+/**
+ * Check if an attribute value as a property is set or not
+ */
+public class IfSetAttribute extends BaseIfAttribute {
+ /** The unless version */
+ public static class Unless extends IfSetAttribute {
+ { setPositive(false); }
+ }
+ /**
+ * check if the attribute value is blank or not
+ * {@inheritDoc}
+ */
+ public boolean isEnabled(UnknownElement el, String value) {
+ return convertResult(getProject().getProperty(value) != null);
+ }
+}
Index: src/main/org/apache/tools/ant/RuntimeConfigurable.java
===================================================================
--- src/main/org/apache/tools/ant/RuntimeConfigurable.java (revision 574890)
+++ src/main/org/apache/tools/ant/RuntimeConfigurable.java (working copy)
@@ -29,6 +29,8 @@
import java.util.Map;
import java.util.Iterator;
+import org.apache.tools.ant.attribute.EnableAttribute;
+
import org.apache.tools.ant.util.CollectionUtils;
import org.xml.sax.AttributeList;
import org.xml.sax.helpers.AttributeListImpl;
@@ -64,6 +66,9 @@
*/
private transient AttributeList attributes;
+ // The following is set to true if any of the attributes are namespaced
+ private transient boolean namespacedAttribute = false;
+
/** Attribute names and values. While the XML spec doesn't require
* preserving the order ( AFAIK ), some ant tests do rely on the
* exact order. The following code is copied from AttributeImpl.
@@ -119,7 +124,74 @@
proxyConfigured = false;
}
+ private static class EnableAttributeConsumer {
+ public void add(EnableAttribute b) {
+ // Ignore
+ }
+ }
+
/**
+ * Check if an UE is enabled.
+ * This looks tru the attributes and checks if there
+ * are any Ant attributes, and if so, the method calls the
+ * isEnabled() method on them.
+ * @param owner the UE that owns this RC.
+ * @return true if enabled, false if any of the ant attribures return
+ * false.
+ */
+ public boolean isEnabled(UnknownElement owner) {
+ if (!namespacedAttribute) {
+ return true;
+ }
+ ComponentHelper componentHelper = ComponentHelper
+ .getComponentHelper(owner.getProject());
+
+ IntrospectionHelper ih
+ = IntrospectionHelper.getHelper(
+ owner.getProject(), EnableAttributeConsumer.class);
+ for (int i = 0; i < attributeNames.size(); ++i) {
+ String name = (String) attributeNames.get(i);
+ if (name.indexOf(':') == -1) {
+ continue;
+ }
+ String componentName = attrToComponent(name);
+ String ns = ProjectHelper.extractUriFromComponentName(componentName);
+ if (componentHelper.getRestrictedDefinitions(
+ ProjectHelper.nsToComponentName(ns)) == null) {
+ continue;
+ }
+
+ String value = (String) attributeMap.get(name);
+
+ EnableAttribute enable = null;
+ try {
+ enable = (EnableAttribute)
+ ih.createElement(
+ owner.getProject(), new EnableAttributeConsumer(),
+ componentName);
+ } catch (BuildException ex) {
+ throw new BuildException(
+ "Unsupported attribute " + componentName);
+ }
+ if (enable == null) {
+ continue;
+ }
+ value = owner.getProject().replaceProperties(value); // FixMe: need to make config
+ if (!enable.isEnabled(owner, value)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private String attrToComponent(String a) {
+ // need to remove the prefix
+ int p1 = a.lastIndexOf(':');
+ int p2 = a.lastIndexOf(':', p1 - 1);
+ return a.substring(0, p2) + a.substring(p1);
+ }
+
+ /**
* Sets the creator of the element to be configured
* used to store the element in the parent.
*
@@ -184,6 +256,9 @@
* @param value the attribute's value.
*/
public synchronized void setAttribute(String name, String value) {
+ if (name.indexOf(':') != -1) {
+ namespacedAttribute = true;
+ }
if (name.equalsIgnoreCase(ProjectHelper.ANT_TYPE)) {
this.polyType = value;
} else {
Index: src/main/org/apache/tools/ant/MagicNames.java
===================================================================
--- src/main/org/apache/tools/ant/MagicNames.java (revision 574890)
+++ src/main/org/apache/tools/ant/MagicNames.java (working copy)
@@ -193,5 +193,8 @@
*/
public static final String REFID_PROJECT_HELPER = "ant.projectHelper";
+ /** Name of the namespace "type" (note: cannot be used as an element)*/
+ public static final String ATTRIBUTE_NAMESPACE = "antribute namespace";
+
}
Index: src/main/org/apache/tools/ant/ProjectHelper.java
===================================================================
--- src/main/org/apache/tools/ant/ProjectHelper.java (revision 574890)
+++ src/main/org/apache/tools/ant/ProjectHelper.java (working copy)
@@ -55,6 +55,9 @@
/** The URI for antlib current definitions */
public static final String ANT_CURRENT_URI = "ant:current";
+ /** The URI for ant specific attributes */
+ public static final String ANT_ATTRIBUTE_URI = "ant:attribute";
+
/** The URI for defined types/tasks - the format is antlib: */
public static final String ANTLIB_URI = "antlib:";
@@ -484,6 +487,15 @@
}
/**
+ * Convert an attribute namespace to a "component name".
+ * @param ns the xml namespace uri.
+ * @return the converted value.
+ */
+ public static String nsToComponentName(String ns) {
+ return "attribute namespace:" + ns;
+ }
+
+ /**
* Add location to build exception.
* @param ex the build exception, if the build exception
* does not include
Index: src/main/org/apache/tools/ant/taskdefs/AttributeNamespaceDef.java
===================================================================
--- src/main/org/apache/tools/ant/taskdefs/AttributeNamespaceDef.java (revision 0)
+++ src/main/org/apache/tools/ant/taskdefs/AttributeNamespaceDef.java (revision 0)
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.ComponentHelper;
+import org.apache.tools.ant.AntTypeDefinition;
+import org.apache.tools.ant.attribute.AttributeNamespace;
+
+/**
+ * Defintion to allow the uri to be considered for
+ * ant attributes.
+ *
+ * @since Ant 1.8.0
+ */
+public final class AttributeNamespaceDef extends AntlibDefinition {
+
+ /**
+ * Run the definition.
+ * This registers the xml namespace (uri) as a namepace for
+ * attributes.
+ */
+ public void execute() {
+ String componentName = ProjectHelper.nsToComponentName(
+ getURI());
+ AntTypeDefinition def = new AntTypeDefinition();
+ def.setName(componentName);
+ def.setClassName(AttributeNamespace.class.getName());
+ def.setClass(AttributeNamespace.class);
+ def.setRestrict(true);
+ def.setClassLoader(AttributeNamespace.class.getClassLoader());
+ ComponentHelper.getComponentHelper(getProject())
+ .addDataTypeDefinition(def);
+ }
+}
Index: src/main/org/apache/tools/ant/taskdefs/defaults.properties
===================================================================
--- src/main/org/apache/tools/ant/taskdefs/defaults.properties (revision 574890)
+++ src/main/org/apache/tools/ant/taskdefs/defaults.properties (working copy)
@@ -4,6 +4,7 @@
antstructure=org.apache.tools.ant.taskdefs.AntStructure
antversion=org.apache.tools.ant.taskdefs.condition.AntVersion
apply=org.apache.tools.ant.taskdefs.Transform
+attributenamespacedef=org.apache.tools.ant.taskdefs.AttributeNamespaceDef
available=org.apache.tools.ant.taskdefs.Available
basename=org.apache.tools.ant.taskdefs.Basename
buildnumber=org.apache.tools.ant.taskdefs.BuildNumber
Index: src/etc/checkstyle/checkstyle-config
===================================================================
--- src/etc/checkstyle/checkstyle-config (revision 574890)
+++ src/etc/checkstyle/checkstyle-config (working copy)
@@ -80,8 +80,8 @@
-
-
+
+
Index: lib/optional/ant-antunit-1.0.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream