/******************************************************************************* * Copyright 2012 André Rouél * * Licensed 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 net.sf.uadetector.internal.data.domain; import java.io.Serializable; import java.util.regex.Pattern; import javax.annotation.Nonnegative; import javax.annotation.Nonnull; import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.NotThreadSafe; import net.sf.qualitycheck.Check; import net.sf.uadetector.internal.util.CompareNullSafe; import net.sf.uadetector.internal.util.RegularExpressionConverter; /** * The {@code OperatingSystemPattern} class represents the detection information for a specific operating system item.<br> * <br> * A {@code OperatingSystemPattern} object is immutable, their values cannot be changed after creation. * * @author André Rouél */ @Immutable public final class OperatingSystemPattern implements Identifiable, OrderedPattern<OperatingSystemPattern>, Serializable { /** * Factory that creates instances of {@code OperatingSystemPattern} via method calls. * * @author André Rouél */ @NotThreadSafe public static final class Builder { /** * Identification number (ID) of an operating system pattern */ private int id = Integer.MIN_VALUE; /** * A compiled representation of a regular expression to detect an operating system */ private Pattern pattern; /** * Position of a {@code OperatingSystemPattern} (only relevant if there are multiple patterns for an operating * system in a {@code SortedSet}) */ private int position = Integer.MIN_VALUE; /** * Builds a new instance of {@code OperatingSystemPattern} and returns it. * * @return a new instance of {@code OperatingSystemPattern} * @throws net.sf.qualitycheck.exception.IllegalNegativeArgumentException * if one of the needed arguments to build an instance of {@code OperatingSystemPattern} is invalid * @throws net.sf.qualitycheck.exception.IllegalNullArgumentException * if one of the needed arguments to build an instance of {@code OperatingSystemPattern} is invalid */ public OperatingSystemPattern build() { return new OperatingSystemPattern(id, pattern, position); } /** * Sets the identification number of an operating system pattern entry. * * @param id * identification number * @return this {@code Builder}, for chaining * @throws net.sf.qualitycheck.exception.IllegalNegativeArgumentException * if the given integer is smaller than {@code 0} */ public Builder setId(final int id) { Check.notNegative(id, "id"); this.id = id; return this; } /** * Sets the identification number (ID) of an operating system pattern. The given {@code String} is parsed as a * decimal number. * * @param id * ID of an operating system pattern as string * @return this {@code Builder}, for chaining * @throws net.sf.qualitycheck.exception.IllegalNullArgumentException * if the given argument is {@code null} * @throws NumberFormatException * if the given string is not parsable as integer * @throws net.sf.qualitycheck.exception.IllegalNegativeArgumentException * if the parsed integer is smaller than {@code 0} */ public Builder setId(@Nonnull final String id) { Check.notEmpty(id, "id"); this.setId(Integer.parseInt(id.trim())); return this; } /** * Sets a regular expression for an operating system pattern. * * @param pattern * compiled representation of a regular expression * @return this {@code Builder}, for chaining */ public Builder setPattern(@Nonnull final Pattern pattern) { Check.notNull(pattern, "pattern"); this.pattern = pattern; return this; } /** * Converts a PERL regular expression in a Java regular expression and sets it in the {@code Builder}. * * @param regex * PERL style regular expression to be converted * @return this {@code Builder}, for chaining */ public Builder setPerlRegularExpression(@Nonnull final String regex) { Check.notEmpty(regex, "regex"); setPattern(RegularExpressionConverter.convertPerlRegexToPattern(regex)); return this; } /** * Sets the position of an operating system pattern in a set of patterns. * * @param position * position of an operating system pattern * @return this {@code Builder}, for chaining * @throws net.sf.qualitycheck.exception.IllegalNegativeArgumentException * if the given integer is smaller than {@code 0} */ public Builder setPosition(@Nonnegative final int position) { Check.notNegative(position, "position"); this.position = position; return this; } /** * Sets the position of an operating system pattern in a set of patterns. The given {@code String} is parsed as * a decimal number. * * @param position * position of an operating system pattern as string * @return this {@code Builder}, for chaining * @throws net.sf.qualitycheck.exception.IllegalNullArgumentException * if the given argument is {@code null} * @throws NumberFormatException * if the given string is not parsable as integer * @throws net.sf.qualitycheck.exception.IllegalNegativeArgumentException * if the parsed integer is smaller than {@code 0} */ public Builder setPosition(@Nonnull final String position) { Check.notEmpty(position, "position"); this.setPosition(Integer.parseInt(position.trim())); return this; } } private static final long serialVersionUID = 1583732916568404647L; /** * Identification number (ID) of an operating system pattern */ @Nonnegative private final int id; /** * A compiled representation of a regular expression to detect an operating system */ @Nonnull private final Pattern pattern; /** * Position of a {@code OperatingSystemPattern} (only relevant if there are multiple patterns for an operating * system in a {@code SortedSet}) */ @Nonnegative private final int position; public OperatingSystemPattern(@Nonnegative final int id, @Nonnull final Pattern pattern, @Nonnegative final int position) { Check.notNegative(id, "id"); Check.notNull(pattern, "pattern"); Check.notNegative(position, "position"); this.id = id; this.pattern = pattern; this.position = position; } /** * Compares all attributes of this instance with the given instance of a {@code OperatingSystemPattern}. * * <p> * This method is <em>consistent with equals</em>. * * @param other * another instance of {@code OperatingSystemPattern} * @return negative value if one of the attributes of this instance is less, 0 if equal, or positive value if * greater than the other one */ @Override public int compareTo(final OperatingSystemPattern other) { int result = other == null ? -1 : 0; if (result == 0) { result = CompareNullSafe.compareInt(getPosition(), other.getPosition()); if (result == 0) { result = CompareNullSafe.compareInt(getId(), other.getId()); } if (result == 0) { result = getPattern().pattern().compareTo(other.getPattern().pattern()); } if (result == 0) { result = CompareNullSafe.compareInt(getPattern().flags(), other.getPattern().flags()); } } return result; } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final OperatingSystemPattern other = (OperatingSystemPattern) obj; if (id != other.id) { return false; } if (position != other.position) { return false; } if (!pattern.pattern().equals(other.pattern.pattern())) { return false; } if (pattern.flags() != other.pattern.flags()) { return false; } return true; } /** * Gets the identification number (ID) of an operating system pattern. * * @return identification number (ID) of an operating system pattern */ @Override public int getId() { return id; } @Override public Pattern getPattern() { return pattern; } @Override public int getPosition() { return position; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + id; result = prime * result + position; result = prime * result + pattern.pattern().hashCode(); result = prime * result + pattern.flags(); return result; } @Override public String toString() { final StringBuilder builder = new StringBuilder(); builder.append("OperatingSystemPattern [id="); builder.append(id); builder.append(", pattern="); builder.append(pattern); builder.append(", position="); builder.append(position); builder.append("]"); return builder.toString(); } }