/*
* Copyright 2010 Bizosys Technologies Limited
*
* Licensed to the Bizosys Technologies Limited (Bizosys) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The Bizosys 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 com.bizosys.hsearch.filter;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Match the Meta and ACL section of document
* @author karan
*
*/
public class AMFilterCommon {
/**
* Read access
*/
public AccessStorable userAcl;
/**
* Check presence inside keywords
*/
public byte[] keyword = null;
/**
* Is state matching
*/
public byte[] state = null;
/**
* Is team matching
*/
public byte[] team = null;
/**
* Created before the Given date
*/
public long maxCreationDate = -1;
/**
* Created after the Given date
*/
public long minCreationDate = -1;
/**
* Modified before the Given date
*/
public long maxModificationDate = -1;
/**
* Modified after the Given date
*/
public long minModificationDate = -1;
/**
* Bytes array
*/
public byte[] bytesA = null;
/**
* Default Constructor
*
*/
public AMFilterCommon() {
}
/**
* Default Constructor - Value object which eventually stored as a byte array
* @param keyword Tagged keywords
* @param state Document state
* @param team Tenant or Organization Unit
* @param createdBefore Created Before
* @param createdAfter Created After
* @param modifiedBefore Modified Before
* @param modifiedAfter Modified After
*/
public AMFilterCommon(AccessStorable viewAcls,
byte[] keyword, byte[] state ,byte[] team,
long createdBefore, long createdAfter,long modifiedBefore, long modifiedAfter ) {
boolean hasAcl = ( null != viewAcls);
boolean hasKeyword = ( null != keyword);
boolean hasState = ( null != state);
boolean hasTeam = ( null != team);
boolean hasCB = ( -1 != createdBefore);
boolean hasCA = ( -1 != createdAfter);
boolean hasMB = ( -1 != modifiedBefore);
boolean hasMA = ( -1 != modifiedAfter);
byte filterFlag = Storable.bitsToByte(new boolean[]{
hasAcl, hasKeyword, hasState,hasTeam,hasCB,hasCA,hasMB,hasMA});
int totalBytes = 1;
byte[] aclB = ( hasAcl) ? viewAcls.toBytes() : null;
if ( hasAcl) totalBytes = totalBytes + aclB.length + 2;
if ( hasKeyword ) totalBytes = totalBytes + keyword.length + 2;
if ( hasState ) totalBytes = totalBytes + state.length + 2;
if ( hasTeam ) totalBytes = totalBytes + team.length + 2;
if ( hasCB ) totalBytes = totalBytes + 8;
if ( hasCA ) totalBytes = totalBytes + 8;
if ( hasMB ) totalBytes = totalBytes + 8;
if ( hasMA ) totalBytes = totalBytes + 8;
byte[] bytes = new byte[totalBytes];
int index=0;
bytes[index++] = filterFlag;
if ( hasAcl ) index = writeBytes(aclB, bytes, index);
if ( hasKeyword ) index = writeBytes(keyword, bytes, index);
if ( hasState ) index = writeBytes(state, bytes, index);
if ( hasTeam ) index = writeBytes(team, bytes, index);
if ( hasCB ) index = writeLong(createdBefore, bytes, index);
if ( hasCA ) index = writeLong(createdAfter, bytes, index);
if ( hasMB ) index = writeLong(modifiedBefore, bytes, index);
if ( hasMA ) index = writeLong(modifiedAfter, bytes, index);
this.bytesA = bytes;
}
/**
* Write the header section
* @param out
* @throws IOException
*/
public void writeHeader(DataOutput out) throws IOException {
out.writeInt(this.bytesA.length);
out.write(this.bytesA);
}
/**
* Read the header section and deserialized the input
* @param in
* @throws IOException
*/
public void readHeader(DataInput in) throws IOException {
int totalB = in.readInt();
this.bytesA = new byte[totalB];
in.readFully(this.bytesA, 0, totalB);
deserialize();
}
/**
* Forms the object from the input byte array
*
*/
public void deserialize() {
int index=0;
byte filterFlag = this.bytesA[index++];
boolean[] filterFlags = Storable.byteToBits(filterFlag);
byte counter = 0;
if ( filterFlags[counter++]) {
short len = Storable.getShort(index, this.bytesA);
index = index + 2;
this.userAcl = new AccessStorable(this.bytesA, index, len);
index = index + len;
}
if ( filterFlags[counter++] ) {
short len = Storable.getShort(index, this.bytesA);
this.keyword = new byte[len];
index = index + 2;
System.arraycopy(this.bytesA, index, this.keyword, 0, len);
index = index + len;
}
if ( filterFlags[counter++] ) {
short len = Storable.getShort(index, this.bytesA);
this.state = new byte[len];
index = index + 2;
System.arraycopy(this.bytesA, index, this.state, 0, len);
index = index + len;
}
if ( filterFlags[counter++] ) {
short len = Storable.getShort(index, this.bytesA);
this.team = new byte[len];
index = index + 2;
System.arraycopy(this.bytesA, index, this.team, 0, len);
index = index + len;
}
if ( filterFlags[counter++]) {
this.maxCreationDate = Storable.getLong(index, this.bytesA);
index = index + 8;
}
if ( filterFlags[counter++]) {
this.minCreationDate = Storable.getLong(index, this.bytesA);
index = index + 8;
}
if ( filterFlags[counter++]) {
this.maxModificationDate = Storable.getLong(index, this.bytesA);
index = index + 8;
}
if ( filterFlags[counter++]) {
this.minModificationDate = Storable.getLong(index, this.bytesA);
index = index + 8;
}
}
/**
* Checks for allowed Access. It scans the block size also.
* @param value Input bytes
* @param pos Read start position
* @return -1 if not Allowed else end position of block
*/
public int allowAccess( byte[] value, int pos) {
boolean isAllowed = false;
if ( null == value ) isAllowed = true;
short len = Storable.getShort(pos, value);
pos = pos + 2;
if ( ! isAllowed ) {
AccessStorable docAcls = FilterObjectFactory.getInstance().getStorableAccess();
docAcls.reset(value,pos,len);
isAllowed = checkAccess(docAcls);
FilterObjectFactory.getInstance().putStorableAccess(docAcls);
if ( ! isAllowed ) return -1;
}
pos = pos + len;
len = Storable.getShort(pos, value);
pos = pos + 2 + len; //editAclB
return pos;
}
private boolean checkAccess(AccessStorable docAcls) {
boolean isAllowed = false;
if ( 0 == docAcls.size() ) isAllowed = true;
else {
for (Object docAclO : docAcls) {
if (compareBytes(0, (byte[]) docAclO, Access.ANY_BYTES)) {
isAllowed = true;
break;
}
if ( null == this.userAcl) return false;
for (Object userAcl : this.userAcl) {
if ( compareBytes(0, (byte[]) docAclO, (byte[]) userAcl) ) {
isAllowed = true;
break;
}
}
if ( isAllowed ) break;
}
}
return isAllowed;
}
public static int measureAccess( byte[] value, int pos) {
int startPos = pos;
if ( null == value ) return -1;
short len = Storable.getShort(pos, value);
pos = pos + 2 + len;
len = Storable.getShort(pos, value);
pos = pos + 2 + len; //editAclB
return (pos - startPos);
}
/**
* Filter meta fields based on user supplied filtering criteria
* @param storedB Stored bytes
* @param pos The starting position
* @return -1 if not Matched else end position of block
*/
public int allowMeta(byte[] storedB, int pos) {
byte docTypeLen = storedB[pos++];
pos = pos + docTypeLen;
byte stateLen = storedB[pos++];
if ( null != state) {
if ( ! compareBytes(pos, storedB, state) ) return -1;
}
pos = pos + stateLen;
byte tenantLen = storedB[pos++];
if ( null != team) {
if ( ! compareBytes(pos, storedB, team) ) return -1;
}
pos = pos + tenantLen;
byte geoLen = storedB[pos++];
pos = pos + geoLen;
byte flag_1B = storedB[pos++];
boolean[] flag_1 = Storable.byteToBits(flag_1B);
byte flag_2B = storedB[pos++];
boolean[] flag_2 = Storable.byteToBits(flag_2B);
int bitPos = 0;
if ( flag_1[bitPos++]) pos = pos+ 4; /** Eastering */
if ( flag_1[bitPos++]) pos = pos+ 4; /** Northing */
if ( flag_1[bitPos++]) pos = pos+ 4; /** Weight */
if ( flag_1[bitPos++]) pos = pos+ 4; /** IP House */
bitPos = bitPos+ 2; /** Security and Sentiment */
if ( flag_1[bitPos++]) { /** Tags Available*/
short len = Storable.getShort(pos, storedB);
pos = pos + 2;
if ( null != this.keyword ) {
if (this.keyword.length > len ) return -1;
if ( -1 == indexOf(storedB, pos, pos+len,
this.keyword, 0, this.keyword.length) ) return -1;
}
pos = pos+ len;
} else {
if ( null != this.keyword ) return -1; //No tags found
}
if ( flag_1[bitPos++]) { //Social text
short len = Storable.getShort(pos, storedB);
pos = pos + 2 + len;
}
bitPos = 0;
if (flag_2[bitPos++]) {
long createdOn = Storable.getLong(pos, storedB);
pos = pos+ 8;
if ( -1 != maxCreationDate) {
if ( maxCreationDate < createdOn) return -1;
}
if ( -1 != minCreationDate) {
if ( minCreationDate > createdOn ) return -1;
}
}
if (flag_2[bitPos++]) {
long modifiedOn = Storable.getLong(pos, storedB);
pos = pos+ 8;
if ( -1 != maxModificationDate) {
if ( maxModificationDate < modifiedOn) return -1;
}
if ( -1 != minModificationDate) {
if ( minModificationDate > modifiedOn ) return -1;
}
}
if (flag_2[bitPos++]) pos = pos+ 8;
return pos;
}
public static int measureMeta(byte[] storedB, int pos) {
int startPos = pos;
byte docTypeLen = storedB[pos++];
pos = pos + docTypeLen;
byte stateLen = storedB[pos++];
pos = pos + stateLen;
byte tenantLen = storedB[pos++];
pos = pos + tenantLen;
byte geoLen = storedB[pos++];
pos = pos + geoLen;
byte flag_1B = storedB[pos++];
boolean[] flag_1 = Storable.byteToBits(flag_1B);
byte flag_2B = storedB[pos++];
boolean[] flag_2 = Storable.byteToBits(flag_2B);
int bitPos = 0;
if ( flag_1[bitPos++]) pos = pos+ 4;
if ( flag_1[bitPos++]) pos = pos+ 4;
if ( flag_1[bitPos++]) pos = pos+ 4;
if ( flag_1[bitPos++]) pos = pos+ 4;
bitPos = bitPos+ 2; /** Security and Sentiment */
if ( flag_1[bitPos++]) { /** Tags Available*/
short len = Storable.getShort(pos, storedB);
pos = pos + 2 + len;
}
if ( flag_1[bitPos++]) { //Social text
short len = Storable.getShort(pos, storedB);
pos = pos + 2 + len;
}
bitPos = 0;
if (flag_2[bitPos++]) pos = pos+ 8;
if (flag_2[bitPos++]) pos = pos+ 8;
if (flag_2[bitPos++]) pos = pos+ 8;
return (pos - startPos);
}
private static boolean compareBytes(int offset,
byte[] inputBytes, byte[] compareBytes) {
int compareBytesT = compareBytes.length;
if ( (offset + compareBytesT) > inputBytes.length ) return false;
if ( compareBytes[0] != inputBytes[offset]) return false;
if ( compareBytes[compareBytesT - 1] != inputBytes[compareBytesT + offset - 1] ) return false;
switch (compareBytesT) {
case 3:
return compareBytes[1] == inputBytes[1 + offset];
case 4:
return compareBytes[1] == inputBytes[1 + offset] &&
compareBytes[2] == inputBytes[2 + offset];
case 5:
return compareBytes[1] == inputBytes[1+ offset] &&
compareBytes[2] == inputBytes[2+ offset] &&
compareBytes[3] == inputBytes[3+ offset];
case 6:
return compareBytes[1] == inputBytes[1+ offset] &&
compareBytes[3] == inputBytes[3+ offset] &&
compareBytes[2] == inputBytes[2+ offset] &&
compareBytes[4] == inputBytes[4+ offset];
default:
compareBytesT--;
for ( int i=0; i< compareBytesT; i++) {
if ( compareBytes[i] != inputBytes[offset + i]) return false;
}
}
return true;
}
private int writeLong(long variable, byte[] bytes, int index) {
System.arraycopy(Storable.putLong(variable),0, bytes, index, 8);
index = index + 8;
return index;
}
private int writeBytes(byte[] variableB, byte[] bytes, int index) {
short variableLen = (short) variableB.length;
bytes[index++] = (byte)(variableLen >> 8 & 0xff);
bytes[index++] = (byte)(variableLen & 0xff);
System.arraycopy(variableB, 0, bytes, index, variableLen);
index = index + variableLen;
return index;
}
static int indexOf(byte[] source, int startPosition, int endPosition,
byte[] target, int targetOffset, int targetCount ) {
byte first = target[targetOffset];
int i = startPosition;
startSearchForFirstChar:
while (true) {
while (i <= endPosition && source[i] != first)i++;
if (i > endPosition) return -1;
int j = i + 1;
int end = j + targetCount - 1;
int k = targetOffset + 1;
while (j < end) {
if (source[j++] != target[k++]) {
i++;
continue startSearchForFirstChar;
}
}
return i - startPosition;
}
}
}