001/**
002 The contents of this file are subject to the Mozilla Public License Version 1.1
003 (the "License"); you may not use this file except in compliance with the License.
004 You may obtain a copy of the License at http://www.mozilla.org/MPL/
005 Software distributed under the License is distributed on an "AS IS" basis,
006 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
007 specific language governing rights and limitations under the License.
008
009 The Original Code is "Varies.java".  Description:
010 "Varies is a Type used as a placeholder for another Type in cases where
011 the appropriate Type is not known until run-time (e.g"
012
013 The Initial Developer of the Original Code is University Health Network. Copyright (C)
014 2001.  All Rights Reserved.
015
016 Contributor(s): ______________________________________.
017
018 Alternatively, the contents of this file may be used under the terms of the
019 GNU General Public License (the "GPL"), in which case the provisions of the GPL are
020 applicable instead of those above.  If you wish to allow use of your version of this
021 file only under the terms of the GPL and not to allow others to use your version
022 of this file under the MPL, indicate your decision by deleting  the provisions above
023 and replace  them with the notice and other provisions required by the GPL License.
024 If you do not delete the provisions above, a recipient may use your version of
025 this file under either the MPL or the GPL.
026
027 */
028
029package ca.uhn.hl7v2.model;
030
031import ca.uhn.hl7v2.HL7Exception;
032import ca.uhn.hl7v2.Location;
033import ca.uhn.hl7v2.parser.EncodingCharacters;
034import ca.uhn.hl7v2.parser.FixFieldDataType;
035import ca.uhn.hl7v2.parser.ModelClassFactory;
036import ca.uhn.hl7v2.parser.ParserConfiguration;
037
038/**
039 * <p>Varies is a Type used as a placeholder for another Type in cases where
040 * the appropriate Type is not known until run-time (e.g. OBX-5).
041 * Parsers and validators may have logic that enforces restrictions on the
042 * Type based on other features of a segment.</p>
043 * <p>If you want to set both the type and the values of a Varies object, you should
044 * set the type first by calling setData(Type t), keeping a reference to your Type,
045 * and then set values by calling methods on the Type.  Here is an example:</p>
046 * <p><code>CN cn = new CN();<br>
047 * variesObject.setData(cn);<br>
048 * cn.getIDNumber().setValue("foo");</code></p>
049 *
050 * @author Bryan Tripp (bryan_tripp@users.sourceforge.net)
051 * @author Andy Pardue
052 */
053@SuppressWarnings("serial")
054public class Varies implements Variable {
055
056    /**
057     * System property key: The value may be set to provide a default
058     * datatype ("ST", "NM", etc) for an OBX segment with a missing
059     * OBX-2 value.
060     *
061     * @deprecated use FixOBX5#DEFAULT_OBX2_TYPE_PROP
062     */
063    public static final String DEFAULT_OBX2_TYPE_PROP = FixFieldDataType.DEFAULT_OBX2_TYPE_PROP;
064
065    /**
066     * System property key: The value may be set to provide a default
067     * datatype ("ST", "NM", etc) for an OBX segment with an invalid
068     * OBX-2 value type. In other words, if OBX-2 has a value of "ZYZYZ",
069     * which is not a valid value, but this property is set to "ST", then
070     * OBX-5 will be parsed as an ST.
071     *
072     * @deprecated use FixOBX5#INVALID_OBX2_TYPE_PROP
073     */
074    public static final String INVALID_OBX2_TYPE_PROP = FixFieldDataType.INVALID_OBX2_TYPE_PROP;
075
076    /**
077     * <p>
078     * System property key: If this is not set, or set to "true", and a subcomponent delimiter is found within the
079     * value of a Varies of a primitive type, this subcomponent delimiter will be treated as a literal
080     * character instead of a subcomponent delimiter, and will therefore be escaped if the message is
081     * re-encoded. This is handy when dealing with non-conformant sending systems which do not correctly
082     * escape ampersands in OBX-5 values.
083     * </p>
084     * <p>
085     * For example, consider the following OBX-5 segment:
086     * <pre>
087     *    OBX||ST|||Apples, Pears &amp; Bananas|||
088     * </pre>
089     * In this example, the data type is a primitive ST and does not support subcomponents, and the
090     * ampersand is obviously not intended to represent a subcomponent delimiter. If this
091     * property is set to <code>true</code>, the entire string will be treated as the
092     * value of OBX-5, and if the message is re-encoded the string will appear
093     * as "Apples, Pears \T\ Bananas".
094     * </p>
095     * <p>
096     * If this property is set to anything other than "true", the subcomponent delimiter is treated as a component delimiter,
097     * so the value after the ampersand is placed into an {@link ExtraComponents extra component}.
098     * </p>
099     *
100     * @deprecated use FixOBX5#ESCAPE_SUBCOMPONENT_DELIM_IN_PRIMITIVE
101     */
102    public static final String ESCAPE_SUBCOMPONENT_DELIM_IN_PRIMITIVE = FixFieldDataType.ESCAPE_SUBCOMPONENT_DELIM_IN_PRIMITIVE;
103
104
105    private Type data;
106    private Message message;
107
108    /**
109     * Creates new Varies.
110     *
111     * @param message message to which this type belongs
112     */
113    public Varies(Message message) {
114        data = new GenericPrimitive(message);
115        this.message = message;
116    }
117
118    /**
119     * Returns the data contained by this instance of Varies.  Returns a GenericPrimitive unless
120     * setData() has been called.
121     *
122     * @return the data contained by this instance of Varies
123     */
124    public Type getData() {
125        return this.data;
126    }
127
128    public String getName() {
129        String name = "*";
130        if (this.data != null) {
131            name = this.data.getName();
132        }
133        return name;
134    }
135
136    /**
137     * Sets the data contained by this instance of Varies.  If a data object already exists,
138     * then its values are copied to the incoming data object before the old one is replaced.
139     * For example, if getData() returns an ST with the value "19901012" and you call
140     * setData(new DT()), then subsequent calls to getData() will return the same DT, with the value
141     * set to "19901012".
142     *
143     * @param data the data to be set for this Varies instance
144     * @throws DataTypeException if the data could not be set
145     */
146    public void setData(Type data) throws DataTypeException {
147        if (this.data != null) {
148            if (!(this.data instanceof Primitive) || ((Primitive) this.data).getValue() != null) {
149                ca.uhn.hl7v2.util.DeepCopy.copy(this.data, data);
150            }
151        }
152        this.data = data;
153    }
154
155    public ExtraComponents getExtraComponents() {
156        return this.data.getExtraComponents();
157    }
158
159    /**
160     * @return the message to which this Type belongs
161     */
162    public Message getMessage() {
163        return message;
164    }
165
166    /**
167     * <p>
168     * Sets the data type of field 5 in the given OBX segment to the value of OBX-2.  The argument
169     * is a Segment as opposed to a particular OBX because it is meant to work with any version.
170     * </p>
171     * <p>
172     * Note that if no value is present in OBX-2, or an invalid value is present in
173     * OBX-2, this method will throw an error. This behaviour can be corrected by using the
174     * following system properties: {@link #DEFAULT_OBX2_TYPE_PROP} and {@link #INVALID_OBX2_TYPE_PROP},
175     * or by using configuration in {@link ParserConfiguration}
176     * </p>
177     *
178     * @param segment OBX segment instance to be modified
179     * @param factory ModelClassFactory to be used
180     * @throws HL7Exception if the operation fails
181     * @deprecated use FixOBX5#fixOBX5
182     */
183    public static void fixOBX5(Segment segment, ModelClassFactory factory) throws HL7Exception {
184        FixFieldDataType.fixOBX5(segment, factory, segment.getMessage().getParser().getParserConfiguration());
185    }
186
187    /**
188     * <p>
189     * Sets the data type of field 5 in the given OBX segment to the value of OBX-2.  The argument
190     * is a Segment as opposed to a particular OBX because it is meant to work with any version.
191     * </p>
192     * <p>
193     * Note that if no value is present in OBX-2, or an invalid value is present in
194     * OBX-2, this method will throw an error. This behaviour can be corrected by using the
195     * following system properties: {@link #DEFAULT_OBX2_TYPE_PROP} and {@link #INVALID_OBX2_TYPE_PROP}
196     * or by using configuration in {@link ParserConfiguration}
197     * </p>
198     *
199     * @param segment             OBX segment instance to be modified
200     * @param factory             ModelClassFactory to be used
201     * @param parserConfiguration configuration that influences setting OBX-5
202     * @throws HL7Exception if the operation fails
203     * @deprecated use FixOBX5#fixOBX5
204     */
205    public static void fixOBX5(Segment segment, ModelClassFactory factory, ParserConfiguration parserConfiguration)
206            throws HL7Exception {
207        FixFieldDataType.fixOBX5(segment, factory, parserConfiguration);
208    }
209
210
211    /**
212     * {@inheritDoc }
213     */
214    public void parse(String string) throws HL7Exception {
215        if (data != null) {
216            data.clear();
217        }
218        getMessage().getParser().parse(this, string, EncodingCharacters.getInstance(getMessage()));
219    }
220
221    /**
222     * {@inheritDoc }
223     */
224    public String encode() throws HL7Exception {
225        return getMessage().getParser().doEncode(this, EncodingCharacters.getInstance(getMessage()));
226    }
227
228    /**
229     * {@inheritDoc }
230     */
231    public void clear() {
232        data.clear();
233    }
234
235    /**
236     * {@inheritDoc }
237     */
238    public boolean isEmpty() throws HL7Exception {
239        return data.isEmpty();
240    }
241
242    /**
243     * {@inheritDoc }
244     */
245    public String toString() {
246        return AbstractType.toString(this);
247    }
248
249    public boolean accept(MessageVisitor visitor, Location currentLocation) throws HL7Exception {
250        return data.accept(visitor, currentLocation);
251    }
252
253    public Location provideLocation(Location location, int index, int repetition) {
254        return data.provideLocation(location, index, repetition);
255    }
256
257}