/* GASH 2 FloatDBField.java The GANYMEDE object storage system. Created: 29 October 1999 Module By: John Knutson, johnk@arlut.utexas.edu ----------------------------------------------------------------------- Ganymede Directory Management System Copyright (C) 1996-2013 The University of Texas at Austin Ganymede is a registered trademark of The University of Texas at Austin Contact information Web site: http://www.arlut.utexas.edu/gash2 Author Email: ganymede_author@arlut.utexas.edu Email mailing list: ganymede@arlut.utexas.edu US Mail: Computer Science Division Applied Research Laboratories The University of Texas at Austin PO Box 8029, Austin TX 78713-8029 Telephone: (512) 835-3200 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package arlut.csd.ganymede.server; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.util.Vector; import arlut.csd.Util.TranslationService; import arlut.csd.ganymede.common.ReturnVal; import arlut.csd.ganymede.rmi.float_field; /*------------------------------------------------------------------------------ class FloatDBField ------------------------------------------------------------------------------*/ /** * <p>FloatDBField is a subclass of {@link * arlut.csd.ganymede.server.DBField DBField} for the storage and * handling of float fields in the {@link * arlut.csd.ganymede.server.DBStore DBStore} on the Ganymede * server.</p> * * <p>The Ganymede client talks to FloatDBFields through the {@link * arlut.csd.ganymede.rmi.float_field float_field} RMI interface.</p> */ public class FloatDBField extends DBField implements float_field { /** * TranslationService object for handling string localization in the * Ganymede server. */ static final TranslationService ts = TranslationService.getTranslationService("arlut.csd.ganymede.server.FloatDBField"); /** * <p>Receive constructor. Used to create a FloatDBField from a * {@link arlut.csd.ganymede.server.DBStore DBStore}/{@link arlut.csd.ganymede.server.DBJournal DBJournal} * DataInput stream.</p> */ FloatDBField(DBObject owner, DataInput in, DBObjectBaseField definition) throws IOException { super(owner, definition.getID()); this.value = null; receive(in, definition); } /** * <p>No-value constructor. Allows the construction of a * 'non-initialized' field, for use where the * {@link arlut.csd.ganymede.server.DBObjectBase DBObjectBase} * definition indicates that a given field may be present, * but for which no value has been stored in the * {@link arlut.csd.ganymede.server.DBStore DBStore}.</p> * * <p>Used to provide the client a template for 'creating' this * field if so desired.</p> */ FloatDBField(DBObject owner, DBObjectBaseField definition) { super(owner, definition.getID()); this.value = null; } /** * * Copy constructor. * */ public FloatDBField(DBObject owner, FloatDBField field) { super(owner, field.getID()); this.value = field.value; } /** * * Scalar value constructor. * */ public FloatDBField(DBObject owner, double value, DBObjectBaseField definition) { super(owner, definition.getID()); this.value = new Double(value); } /** * * Vector value constructor. * */ public FloatDBField(DBObject owner, Vector values, DBObjectBaseField definition) { super(owner, definition.getID()); throw new IllegalArgumentException("vector constructor called on scalar field"); } public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } @Override void emit(DataOutput out) throws IOException { out.writeDouble(((Double) value).doubleValue()); } @Override void receive(DataInput in, DBObjectBaseField definition) throws IOException { value = new Double(in.readDouble()); } /** * <p>This method is used when the database is being dumped, to write * out this field to disk.</p> */ @Override synchronized void emitXML(XMLDumpContext xmlOut) throws IOException { xmlOut.startElementIndent(this.getXMLName()); emitDoubleXML(xmlOut, value()); xmlOut.endElement(this.getXMLName()); } public void emitDoubleXML(XMLDumpContext xmlOut, double value) throws IOException { xmlOut.startElement("float"); xmlOut.attribute("val", java.lang.Double.toString(value)); xmlOut.endElement("float"); } // **** // // type-specific accessor methods // // **** public double value() { if (isVector()) { throw new IllegalArgumentException("scalar accessor called on vector field"); } return ((Double) value).doubleValue(); } public double value(int index) { // float can't be a vector field throw new IllegalArgumentException("vector accessor called on scalar field"); } @Override public synchronized String getValueString() { if (value == null) { return ""; } return Double.toString(this.value()); } /** * * For numbers, our default getValueString() encoding is adequate. * */ @Override public String getEncodingString() { return getValueString(); } /** * <p>Returns a String representing the change in value between this * field and orig. This String is intended for logging and email, * not for any sort of programmatic activity. The format of the * generated string is not defined, but is intended to be suitable * for inclusion in a log entry and in an email message.</p> * * <p>If there is no change in the field, null will be returned.</p> */ @Override public String getDiffString(DBField orig) { FloatDBField origN; /* -- */ if (!(orig instanceof FloatDBField)) { throw new IllegalArgumentException("bad field comparison"); } origN = (FloatDBField) orig; if (origN.value() != this.value()) { // "\tOld: {0,number}\n\tNew: {1,number}\n" return ts.l("getDiffString.pattern", new Double(origN.value()), new Double(this.value())); } else { return null; } } // **** // // float_field specific methods // // **** /** * * Returns true if this field has max/min * limitations. * * @see arlut.csd.ganymede.rmi.float_field * */ public boolean limited() { DBEditObject eObj; /* -- */ if (!isEditable(true)) { throw new IllegalArgumentException("not applicable to a non-editable field/object"); } eObj = (DBEditObject) this.owner; return eObj.isFloatLimited(this); } /** * * Returns the minimum acceptable value for this field if this field * has max/min limitations. * * @see arlut.csd.ganymede.rmi.float_field * */ public double getMinValue() { DBEditObject eObj; /* -- */ if (!isEditable(true)) { throw new IllegalArgumentException("not applicable to a non-editable field/object"); } eObj = (DBEditObject) this.owner; return eObj.minFloat(this); } /** * * Returns the maximum acceptable value for this field if this field * has max/min limitations. * * @see arlut.csd.ganymede.rmi.float_field * */ public double getMaxValue() { DBEditObject eObj; /* -- */ if (!isEditable(true)) { throw new IllegalArgumentException("not applicable to a non-editable field/object"); } eObj = (DBEditObject) this.owner; return eObj.maxFloat(this); } // **** // // Overridable methods for implementing intelligent behavior // // **** @Override public boolean verifyTypeMatch(Object o) { return ((o == null) || (o instanceof Double)); } @Override public ReturnVal verifyNewValue(Object o) { DBEditObject eObj; Double I; /* -- */ eObj = (DBEditObject) this.owner; if (!verifyTypeMatch(o)) { // "Float Field Error" // "Submitted value {0} is not a Double! Major client error while trying to edit field {1} in object {2}." return Ganymede.createErrorDialog(ts.l("global.error_subj"), ts.l("verifyNewValue.type_error", o, getName(), eObj.getLabel())); } if (o == null) { return eObj.verifyNewValue(this, null); // explicit for FindBugs } I = (Double) o; if (limited()) { if (getMinValue() > I.doubleValue()) { // "Float Field Error" // "Submitted float {0} is out of range for field {1} in object {2}. This field will not accept floats less than {3}." return Ganymede.createErrorDialog(ts.l("global.error_subj"), ts.l("verifyNewValue.low_value_error", I, getName(), eObj.getLabel(), new Double(getMinValue()))); } if (getMaxValue() < I.doubleValue()) { // "Float Field Error" // "Submitted float {0} is out of range for field {1} in object {2}. This field will not accept floats greater than {3}." return Ganymede.createErrorDialog(ts.l("global.error_subj"), ts.l("verifyNewValue.high_value_error", I, getName(), eObj.getLabel(), new Double(getMaxValue()))); } } // have our parent make the final ok on the value return eObj.verifyNewValue(this, o); } }