/* * Copyright Ericsson AB 2011-2014. All Rights Reserved. * * The contents of this file are subject to the Lesser GNU Public License, * (the "License"), either version 2.1 of the License, or * (at your option) any later version.; you may not use this file except in * compliance with the License. You should have received a copy of the * License along with this software. If not, it can be * retrieved online at https://www.gnu.org/licenses/lgpl.html. Moreover * it could also be requested from Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO * WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. * EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR * OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, * EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE * LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, * YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. * * IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING * WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR * REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR * DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL * DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY * (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED * INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE * OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH * HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * */ package com.ericsson.deviceaccess.spi.schema; import com.ericsson.common.util.serialization.Format; import com.ericsson.common.util.serialization.SerializationException; import com.ericsson.common.util.serialization.SerializationUtil; import com.ericsson.deviceaccess.api.Constants; import com.ericsson.deviceaccess.api.genericdevice.GDAccessPermission.Type; import com.ericsson.deviceaccess.api.genericdevice.GDException; import com.ericsson.deviceaccess.api.genericdevice.GDPropertyMetadata; import com.ericsson.deviceaccess.spi.genericdevice.GDAccessSecurity; import java.util.Arrays; /** * */ public class ParameterSchema implements GDPropertyMetadata { private String name; private Number minValue; private Number maxValue; private Object defaultValue; private Class<?> type; private String[] validValues; private String path; /** * @param name * @param type one of * {@link String.class}, {@link Integer.class}, {@link Long.class} or * {@link Float.class} * @param defaultValue */ private ParameterSchema(String name, Class<?> type, Object defaultValue) { if (defaultValue != null && !type.isAssignableFrom(defaultValue.getClass())) { throw new ServiceSchemaError("Default value is not of type: " + type); } if (Float.class.isAssignableFrom(type)) { minValue = Float.NEGATIVE_INFINITY; maxValue = Float.POSITIVE_INFINITY; } else if (Integer.class.isAssignableFrom(type)) { minValue = Integer.MIN_VALUE; maxValue = Integer.MAX_VALUE; } else if (Long.class.isAssignableFrom(type)) { minValue = Long.MIN_VALUE; maxValue = Long.MAX_VALUE; } else if (!String.class.isAssignableFrom(type)) { throw new ServiceSchemaError("Parameter must be of type Long, Integer, Float or String"); } this.name = name; this.type = type; this.defaultValue = defaultValue; } /** * {@inheritDoc} */ @Override public String getName() { return name; } /** * {@inheritDoc} */ @Override public Class getType() { return type; } /** * {@inheritDoc} */ @Override public String getTypeName() { if (type == String.class) { return "String"; } else if (type == Float.class) { return "Float"; } else if (type == Integer.class) { return "Integer"; } else if (type == Long.class) { return "Long"; } else { //TODO: Should we cast an exception if the argument type is not string, float or integer? return type.getName(); } } /** * {@inheritDoc} */ @Override public Number getMinValue() { return minValue; } /** * {@inheritDoc} */ @Override public Number getMaxValue() { return maxValue; } /** * {@inheritDoc} */ @Override public Number getDefaultNumberValue() { return (Number) defaultValue; } /** * {@inheritDoc} */ @Override public String getDefaultStringValue() { return defaultValue + ""; } /** * {@inheritDoc} */ @Override public String[] getValidValues() { return validValues; } /** * {@inheritDoc} */ @Override public String serialize(Format format) throws GDException { try { return SerializationUtil.execute(format, mapper -> mapper.writeValueAsString(this)); } catch (SerializationException ex) { throw new GDException(ex.getMessage(), ex); } } /** * {@inheritDoc} */ @Override public String getSerializedNode(String path, Format format) throws GDException { try { return SerializationUtil.serializeAccordingPath(format, path, Constants.PATH_DELIMITER, this); } catch (SerializationException ex) { throw new GDException(404, ex.getMessage(), ex); } } /** * {@inheritDoc} */ @Override public String getPath(boolean isAbsolute) { return path + "/parameter/" + this.getName(); } /** * {@inheritDoc} */ @Override public String getPath() { GDAccessSecurity.checkPermission(getClass(), Type.GET); return path + "/parameter/" + this.getName(); } /** * {@inheritDoc} */ @Override public void updatePath(String path) { GDAccessSecurity.checkPermission(getClass(), Type.SET); this.path = path; } public static class Builder { private String name; private Number minValue; private Number maxValue; private Object defaultValue; private Class<?> type; private String[] validValues; /** * Creates a builder for a parameter with the specified name. * */ public Builder() { } public Builder(String name, Class<?> type) { this.name = name; this.type = type; } public Builder setName(String name) { this.name = name; return this; } public Builder setType(Class type) { this.type = type; return this; } /** * Sets the min value. The string will be interpreted according to the * type of the parameter schema. * * @param minValue * @return this parameter schema */ public Builder setMinValue(String minValue) { if (isSuperOf(Float.class, type)) { this.minValue = Float.valueOf(minValue); } else if (isSuperOf(Integer.class, type)) { this.minValue = Integer.decode(minValue); } else if (isSuperOf(Long.class, type)) { this.minValue = Long.decode(minValue); } else { throw new ServiceSchemaError("Cannot set min value when the parameter type is " + type); } return this; } /** * Sets the max value. The string will be interpreted according to the * type of the parameter schema. * * @param maxValue * @return this parameter schema */ public Builder setMaxValue(String maxValue) { if (isSuperOf(Float.class, type)) { this.maxValue = Float.valueOf(maxValue); } else if (isSuperOf(Integer.class, type)) { this.maxValue = Integer.decode(maxValue); } else if (isSuperOf(Long.class, type)) { this.maxValue = Long.decode(maxValue); } else { throw new ServiceSchemaError("Cannot set max value when the parameter type is " + type); } return this; } /** * @param defaultValue the defaultValue to set * @return the builder */ public Builder setDefault(String defaultValue) { try { if (isSuperOf(Float.class, type)) { this.defaultValue = Float.valueOf(defaultValue); } else if (isSuperOf(Integer.class, type)) { this.defaultValue = Integer.decode(defaultValue); } else if (isSuperOf(Long.class, type)) { this.defaultValue = Long.decode(defaultValue); } else { this.defaultValue = defaultValue; } } catch (NumberFormatException ex) { throw new ServiceSchemaError(ex); } return this; } /** * @param validValues the validValues to set * @return the builder */ public Builder setValidValues(String... validValues) { this.validValues = validValues; return this; } /** * Builds the schema. * * @return the built schema */ public ParameterSchema build() { if (name == null) { throw new ServiceSchemaError("Name must be specified"); } if (!(isSuperOf(Long.class, type) || isSuperOf(Integer.class, type) || isSuperOf(Float.class, type) || isSuperOf(String.class, type))) { throw new ServiceSchemaError("Parameter must be of type Long, Integer, Float or String"); } if (defaultValue == null) { if (isSuperOf(String.class, type)) { defaultValue = ""; } else if (isSuperOf(Integer.class, type)) { defaultValue = 0; } else if (isSuperOf(Long.class, type)) { defaultValue = 0l; } else if (isSuperOf(Float.class, type)) { defaultValue = 0.0f; } } ParameterSchema parameterSchema = new ParameterSchema(name, type, defaultValue); if (isSuperOf(Float.class, type)) { minValue = minValue == null ? new Float(Float.NEGATIVE_INFINITY) : minValue; if (!isSuperOf(Float.class, minValue.getClass())) { throw new ServiceSchemaError("Min value type (" + minValue.getClass() + ") does not match parameter type (" + type + ")"); } parameterSchema.minValue = minValue; maxValue = maxValue == null ? new Float(Float.POSITIVE_INFINITY) : maxValue; if (!isSuperOf(Float.class, maxValue.getClass())) { throw new ServiceSchemaError("Max value type (" + maxValue.getClass() + ") does not match parameter type (" + type + ")"); } parameterSchema.maxValue = maxValue; } else if (isSuperOf(Integer.class, type)) { minValue = minValue == null ? new Integer(Integer.MIN_VALUE) : minValue; if (!isSuperOf(Integer.class, minValue.getClass())) { throw new ServiceSchemaError("Min value type (" + minValue.getClass() + ") does not match parameter type (" + type + ")"); } parameterSchema.minValue = minValue; maxValue = maxValue == null ? new Integer(Integer.MAX_VALUE) : maxValue; if (!isSuperOf(Integer.class, maxValue.getClass())) { throw new ServiceSchemaError("Max value type (" + maxValue.getClass() + ") does not match parameter type (" + type + ")"); } parameterSchema.maxValue = maxValue; } else if (isSuperOf(Long.class, type)) { minValue = minValue == null ? new Long(Long.MIN_VALUE) : minValue; if (!isSuperOf(Long.class, minValue.getClass())) { throw new ServiceSchemaError("Min value type (" + minValue.getClass() + ") does not match parameter type (" + type + ")"); } parameterSchema.minValue = minValue; maxValue = maxValue == null ? new Long(Long.MAX_VALUE) : maxValue; if (!isSuperOf(Long.class, maxValue.getClass())) { throw new ServiceSchemaError("Max value type (" + maxValue.getClass() + ") does not match parameter type (" + type + ")"); } parameterSchema.maxValue = maxValue; } if (isSuperOf(String.class, type)) { if (validValues != null) { Arrays.sort(validValues); if (Arrays.binarySearch(validValues, defaultValue) < 0) { throw new ServiceSchemaError("Default value (" + defaultValue + ") is not among valid values."); } parameterSchema.validValues = validValues; } } else { if (validValues != null) { throw new ServiceSchemaError("Valid values are set on a non-string schema"); } } return parameterSchema; } private boolean isSuperOf(Class a, Class b) { return a.isAssignableFrom(b); } } }