001: /*
002: * Copyright 2005 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package com.opensymphony.xwork.util.location;
017:
018: import java.io.Serializable;
019:
020: /**
021: * A simple immutable and serializable implementation of {@link Location}.
022: */
023: public class LocationImpl implements Location, Serializable {
024: private final String uri;
025: private final int line;
026: private final int column;
027: private final String description;
028:
029: // Package private: outside this package, use Location.UNKNOWN.
030: static final LocationImpl UNKNOWN = new LocationImpl(null, null,
031: -1, -1);
032:
033: /**
034: * Build a location for a given URI, with unknown line and column numbers.
035: *
036: * @param uri the resource URI
037: */
038: public LocationImpl(String description, String uri) {
039: this (description, uri, -1, -1);
040: }
041:
042: /**
043: * Build a location for a given URI and line and column numbers.
044: *
045: * @param uri the resource URI
046: * @param line the line number (starts at 1)
047: * @param column the column number (starts at 1)
048: */
049: public LocationImpl(String description, String uri, int line,
050: int column) {
051: if (uri == null || uri.length() == 0) {
052: this .uri = null;
053: this .line = -1;
054: this .column = -1;
055: } else {
056: this .uri = uri;
057: this .line = line;
058: this .column = column;
059: }
060:
061: if (description != null && description.length() == 0) {
062: description = null;
063: }
064: this .description = description;
065: }
066:
067: /**
068: * Copy constructor.
069: *
070: * @param location the location to be copied
071: */
072: public LocationImpl(Location location) {
073: this (location.getDescription(), location.getURI(), location
074: .getLineNumber(), location.getColumnNumber());
075: }
076:
077: /**
078: * Create a location from an existing one, but with a different description
079: */
080: public LocationImpl(String description, Location location) {
081: this (description, location.getURI(), location.getLineNumber(),
082: location.getColumnNumber());
083: }
084:
085: /**
086: * Obtain a <code>LocationImpl</code> from a {@link Location}. If <code>location</code> is
087: * already a <code>LocationImpl</code>, it is returned, otherwise it is copied.
088: * <p>
089: * This method is useful when an immutable and serializable location is needed, such as in locatable
090: * exceptions.
091: *
092: * @param location the location
093: * @return an immutable and serializable version of <code>location</code>
094: */
095: public static LocationImpl get(Location location) {
096: if (location instanceof LocationImpl) {
097: return (LocationImpl) location;
098: } else if (location == null) {
099: return UNKNOWN;
100: } else {
101: return new LocationImpl(location);
102: }
103: }
104:
105: /**
106: * Get the description of this location
107: *
108: * @return the description (can be <code>null</code>)
109: */
110: public String getDescription() {
111: return this .description;
112: }
113:
114: /**
115: * Get the URI of this location
116: *
117: * @return the URI (<code>null</code> if unknown).
118: */
119: public String getURI() {
120: return this .uri;
121: }
122:
123: /**
124: * Get the line number of this location
125: *
126: * @return the line number (<code>-1</code> if unknown)
127: */
128: public int getLineNumber() {
129: return this .line;
130: }
131:
132: /**
133: * Get the column number of this location
134: *
135: * @return the column number (<code>-1</code> if unknown)
136: */
137: public int getColumnNumber() {
138: return this .column;
139: }
140:
141: public boolean equals(Object obj) {
142: if (obj == this ) {
143: return true;
144: }
145:
146: if (obj instanceof Location) {
147: Location other = (Location) obj;
148: return this .line == other.getLineNumber()
149: && this .column == other.getColumnNumber()
150: && testEquals(this .uri, other.getURI())
151: && testEquals(this .description, other
152: .getDescription());
153: }
154:
155: return false;
156: }
157:
158: public int hashCode() {
159: int hash = line ^ column;
160: if (uri != null)
161: hash ^= uri.hashCode();
162: if (description != null)
163: hash ^= description.hashCode();
164:
165: return hash;
166: }
167:
168: public String toString() {
169: return LocationUtils.toString(this );
170: }
171:
172: /**
173: * Ensure serialized unknown location resolve to {@link Location#UNKNOWN}.
174: */
175: private Object readResolve() {
176: return this .equals(Location.UNKNOWN) ? Location.UNKNOWN : this ;
177: }
178:
179: private boolean testEquals(Object object1, Object object2) {
180: if (object1 == object2) {
181: return true;
182: }
183: if ((object1 == null) || (object2 == null)) {
184: return false;
185: }
186: return object1.equals(object2);
187: }
188: }
|