blob: 3ccabeb0dff78895e1c26c09a55a23805f5e1c19 [file] [log] [blame]
/*
* 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.sis.parameter;
import javax.measure.Unit;
import javax.xml.bind.annotation.XmlTransient;
import org.opengis.parameter.ParameterValue;
import org.apache.sis.internal.util.Cloner;
import org.apache.sis.util.collection.WeakHashSet;
import org.apache.sis.util.resources.Errors;
/**
* A parameter value which can not be modified. This implementation shall be used only with:
*
* <ul>
* <li>immutable {@linkplain #getDescriptor() descriptor},</li>
* <li>immutable or null {@linkplain #getUnit() unit}, and</li>
* <li>immutable or {@linkplain Cloneable cloneable} parameter {@linkplain #getValue() value}.</li>
* </ul>
*
* If the parameter value implements the {@link Cloneable} interface and has a public {@code clone()} method,
* then that value will be cloned every time the {@link #getValue()} method is invoked.
* The value is not cloned by this method however; it is caller's responsibility to not modify the value of
* the given {@code parameter} instance after this method call.
*
* <div class="section">Instances sharing</div>
* If the {@link #create(ParameterValue)} method is invoked more than once with equal descriptor, value and unit,
* then the method will return the same {@code UnmodifiableParameterValue} instance on a <cite>best effort</cite>
* basis.
*
* <div class="note"><b>Rational:</b>
* the same parameter value is often used in many different coordinate operations. For example all <cite>Universal
* Transverse Mercator</cite> (UTM) projections use the same scale factor (0.9996) and false easting (500000 metres).
* </div>
*
* @author Martin Desruisseaux (Geomatys)
* @version 0.6
*
* @param <T> the type of the value stored in this parameter.
*
* @since 0.6
* @module
*/
@XmlTransient
final class UnmodifiableParameterValue<T> extends DefaultParameterValue<T> {
/**
* For cross-version compatibility.
*/
private static final long serialVersionUID = -4760030766220872555L;
/**
* Pool of parameter instances created in this running JVM.
* See class javadoc for a rational about why we use a pool.
*/
@SuppressWarnings("rawtypes")
private static final WeakHashSet<UnmodifiableParameterValue> POOL =
new WeakHashSet<>(UnmodifiableParameterValue.class);
/**
* Creates a new parameter with the same value than the given one.
*/
private UnmodifiableParameterValue(final ParameterValue<T> value) {
super(value);
}
/**
* Returns an unmodifiable implementation of the given parameter value.
* See class javadoc for more information.
*
* @param <T> the type of the value stored in the given parameter.
* @param parameter the parameter to make unmodifiable, or {@code null}.
* @return an unmodifiable implementation of the given parameter, or {@code null} if the given parameter was null.
*/
static <T> UnmodifiableParameterValue<T> create(final ParameterValue<T> parameter) {
if (parameter == null || parameter instanceof UnmodifiableParameterValue<?>) {
return (UnmodifiableParameterValue<T>) parameter;
} else {
return POOL.unique(new UnmodifiableParameterValue<>(parameter));
}
}
/**
* If the value is cloneable, clones it before to return it.
*/
@Override
public T getValue() {
T value = super.getValue();
if (value instanceof Cloneable) try {
value = getDescriptor().getValueClass().cast(Cloner.cloneIfPublic(value));
} catch (CloneNotSupportedException e) {
throw new UnsupportedOperationException(Errors.format(Errors.Keys.CloneNotSupported_1, value.getClass()), e);
}
return value;
}
/**
* Do not allow modification of the parameter value.
*/
@Override
protected void setValue(final Object value, final Unit<?> unit) {
throw new UnsupportedOperationException(Errors.format(Errors.Keys.UnmodifiableObject_1, getClass()));
}
/**
* Returns a modifiable copy of this parameter.
*/
@Override
@SuppressWarnings("CloneDoesntCallSuperClone")
public DefaultParameterValue<T> clone() {
return new DefaultParameterValue<>(this);
}
}