/**
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
licenses@blazegraph.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.bigdata.rdf.internal.impl.literal;
import java.io.Serializable;
import java.net.UnknownHostException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.log4j.Logger;
import org.openrdf.model.Literal;
import com.bigdata.rdf.internal.DTE;
import com.bigdata.rdf.internal.DTEExtension;
import com.bigdata.rdf.internal.IPv4Address;
import com.bigdata.rdf.internal.IV;
import com.bigdata.rdf.internal.XSD;
import com.bigdata.rdf.lexicon.LexiconRelation;
import com.bigdata.rdf.model.BigdataLiteral;
import com.bigdata.util.BytesUtil;
/**
* Internal value representing an inline IP address. Uses the IPv4Address class
* to represent the IP address and perform the translation to and from a
* <code>byte[]</code>, which is then used directly in the IV key (after the
* flags).
* <p>
* {@inheritDoc}
* <p>
* Note: Binary compatibility for this class was broken by BLZG-1507.
*
* @see BLZG-1507 (Implement support for DTE extension types for URIs)
*/
public class IPv4AddrIV<V extends BigdataLiteral>
extends AbstractLiteralIV<V, IPv4Address>
implements Serializable, Literal {
/**
*
*/
private static final long serialVersionUID = 685148537376856907L;
private static final transient Logger log = Logger.getLogger(IPv4AddrIV.class);
/**
* The inline IP address.
*/
private final IPv4Address value;
/**
* The cached string representation of this IP.
*/
private transient String hostAddress;
/**
* The cached materialized BigdataValue for this InetAddress.
*/
private transient V uri;
@Override
public IV<V, IPv4Address> clone(final boolean clearCache) {
final IPv4AddrIV<V> tmp = new IPv4AddrIV<V>(value);
// Propagate the cached BigdataValue.
tmp.uri = uri;
if (!clearCache) {
tmp.setValue(getValueCache());
}
return tmp;
}
/**
* Ctor with internal value specified.
*/
public IPv4AddrIV(final IPv4Address value) {
super(DTE.Extension);
this.value = value;
}
/**
* Regex pattern for IPv4 Address with optional CIDR
*/
private static transient final String IPv4_OPTIONAL_CIDR_PATTERN = "((([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5]))(\\/([012]?\\d|3[012]))?";
// "((?:[0-9]{1,3}\\.){3}[0-9]{1,3})((\\/)(([0-9]{1,2})))?
private static transient final Pattern pattern =
Pattern.compile(IPv4_OPTIONAL_CIDR_PATTERN);
/**
* Ctor with host address specified.
*
* @throws UnknownHostException
* if not parsable as an IPv4 address.
*/
public IPv4AddrIV(final String hostAddress) throws UnknownHostException {
super(DTE.Extension);
this.hostAddress = hostAddress;
final Matcher matcher = pattern.matcher(hostAddress);
final boolean matches = matcher.matches();
if (matches) {
final String ip = matcher.group(1);
if (log.isDebugEnabled())
log.debug(ip);
final String suffix = matcher.group(6);
if (log.isDebugEnabled())
log.debug(suffix);
final String[] s;
if (suffix != null) {
s = new String[5];
System.arraycopy(ip.split("\\.", -1), 0, s, 0, 4);
s[4] = suffix;
} else {
s = ip.split("\\.", -1);
}
this.value = IPv4Address.IPv4Factory(s);
if (value == null) {
if (log.isDebugEnabled()) {
log.debug("not a valid IP: " + hostAddress);
}
throw new UnknownHostException("not a valid IP: " + hostAddress);
}
if (log.isDebugEnabled()) {
log.debug(value);
log.debug(byteLength());
log.debug(BytesUtil.toString(value.getBytes()));
}
} else {
if (log.isDebugEnabled()) {
log.debug("not a valid IP: " + hostAddress);
}
throw new UnknownHostException("Did not match REGEX - not a valid IP: " + hostAddress);
}
}
@Override
public DTEExtension getDTEX() {
return DTEExtension.IPV4;
}
@Override
public IPv4Address getInlineValue() throws UnsupportedOperationException {
return value;
}
@Override
@SuppressWarnings("unchecked")
public V asValue(final LexiconRelation lex) {
if (uri == null) {
uri = (V) lex.getValueFactory().createLiteral(getLabel(), XSD.IPV4);
uri.setIV(this);
}
return uri;
}
@Override
public int byteLength() {
return 1 /* flags */ + 1 /* DTEExtension */ + value.getBytes().length;
}
@Override
public String toString() {
return "IPv4(" + getLabel() + ")";
}
@Override
public int hashCode() {
return value.hashCode();
}
@Override
public String getLabel() {
if (hostAddress == null) {
hostAddress = value.toString();
}
return hostAddress;
}
/**
* Two {@link IPv4AddrIV} are equal if their InetAddresses are equal.
*/
@Override
public boolean equals(final Object o) {
if (this == o)
return true;
if (o instanceof IPv4AddrIV) {
final IPv4Address value2 = ((IPv4AddrIV<?>) o).value;
return value.equals(value2);
}
return false;
}
@Override
@SuppressWarnings("rawtypes")
public int _compareTo(final IV o) {
return value.compareTo(((IPv4AddrIV) o).value);
}
public static Matcher getIPv4Matcher(String addr) {
return IPv4AddrIV.pattern.matcher(addr);
}
}