package iitb.con.net;
import iitb.con.core.Attribute;
import iitb.con.core.ConStoreConstants;
import iitb.con.core.Entity;
import iitb.con.core.Instance;
import iitb.con.core.Relation;
import iitb.con.core.RelationInstance;
import iitb.con.core.Type;
import iitb.con.ds.InstanceMetaItem;
import iitb.con.ds.InstanceTableFactory;
import iitb.con.ds.ItemTable;
import iitb.con.ds.Node;
import iitb.con.ds.RelationTable;
import iitb.con.ds.TypeTableFactory;
import iitb.con.indexing.IndexBuilder;
import iitb.con.net.codegenerator.CodeGenerator;
import iitb.con.query.ItemQuery;
import iitb.con.query.Query;
import iitb.con.util.FileUtil;
import iitb.con.util.PropertiesConfig;
import iitb.con.util.Result;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
public class FileConceptNet extends ConceptNet {
private boolean readOnly;
private boolean typeDirtFlag;
private boolean instanceDirtFlag;
private ItemTable<String, Short, Type> typeTable;
private ItemTable<Short, Integer, InstanceMetaItem> instanceTable;
private RelationTable relationTable;
private List<Type> typeList;
private short typeId = -1;
private int instanceId = -1;
private Properties properties;
public FileConceptNet(String name, String mode)
throws FileNotFoundException, IOException {
properties = PropertiesConfig.loadProperties(ConceptNetDir + ConStoreConstants.PROPERTIES_FILE);
if(mode.equals("r")) {
readOnly = true;
}else if(mode.equals("rw")) {
readOnly = false;
typeId = Short.parseShort(properties.getProperty("TYPE_ID"));
instanceId = Integer.parseInt(properties.getProperty("INSTANCE_ID"));
typeList = new ArrayList<Type>();
}else{
throw new IOException("Invalid opening mode");
}
ConStoreConstants.IO_BUFFER_SIZE = Integer.parseInt(properties.getProperty("IO_BUFFER_SIZE"));
ConStoreConstants.QUERY_CACHE_SIZE = Long.parseLong(properties.getProperty("QUERY_CACHE_SIZE"));
ConStoreConstants.INSTANCE_CACHE_SIZE = Long.parseLong(properties.getProperty("INSTANCE_CACHE_SIZE"));
typeTable = TypeTableFactory.getTypeTable(ConceptNetDir + ConStoreConstants.META_FILE, mode);
instanceTable = InstanceTableFactory.getInstanceTable(ConceptNetDir, mode);
relationTable = new RelationTable(ConceptNetDir,
ConStoreConstants.INSTANCE_CACHE_SIZE);
typeDirtFlag = false;
instanceDirtFlag = false;
}
public Result induct(Type type) {
if(type !=null) {
if(type.name != null && !type.name.equals("")) {
if(typeTable.get(type.name, null) == null) {
type.id = ++typeId;
typeTable.put(type);
typeDirtFlag = true;
typeList.add(type);
return new Result(true,"Type '" + type.name + "' inducted successfully");
}else {
return new Result(false,"Type with the name '" + type.name
+ "' already exists");
}
}else{
return new Result(false,"Invalid Type name '" + type.name + "'");
}
}else{
return new Result(false,"Null Object");
}
}
public Type getType(String name) {
return typeTable.get(name, null);
}
public boolean hasType(String name) {
if(typeTable.get(name,null) != null)
return true;
else
return false;
}
public int add(Instance instance) {
InstanceMetaItem metaItem = createInstaneMeta(instance);
return storeInstance(instance, metaItem);
}
private int storeInstance(Instance instance, InstanceMetaItem metaItem) {
instanceTable.put(metaItem);
if(instance instanceof RelationInstance)
addRelation((RelationInstance)instance);
instanceDirtFlag= true;
return metaItem.instanceId;
}
public Result update(Instance instance) {
InstanceMetaItem instanceItem = instanceTable.get(instance.id);
if(instanceItem != null) {
instanceItem.instance = instance;
instanceTable.put(instanceItem);
if(instance instanceof RelationInstance)
updateRelation((RelationInstance)instance);
instanceDirtFlag = true;
return new Result(true);
}else {
return new Result(false, "Instance does not exists");
}
}
public Result remove(Instance instance) {
if(instance instanceof RelationInstance)
removeRelation((RelationInstance)instance);
else
relationTable.removeInstance(instance.id);
instanceTable.remove(instance.typeId, instance.id);
instanceDirtFlag = true;
return new Result(true);
}
public Result remove(int instanceId) {
instanceTable.remove(instanceId);
relationTable.removeInstance(instanceId);
relationTable.removeRelation(instanceId);
instanceDirtFlag = true;
return new Result(true);
}
private void addRelation(RelationInstance instance) {
Type type = getType(instance.getClass().getSimpleName());
instance.setType(type);
relationTable.insert(instance.leftInstanceId, instance.id, instance.rightInstanceId);
if(instance.getDirection() == Relation.BIDIRECTIONAL)
relationTable.insert(instance.rightInstanceId, instance.id, instance.leftInstanceId);
}
private void updateClusterLabel(int leftInstanceId, int rightInstanceId) {
InstanceMetaItem leftItem = instanceTable.get(leftInstanceId);
InstanceMetaItem rightItem = instanceTable.get(rightInstanceId);
if(leftItem != null && rightItem != null) {
short leftLabel = leftItem.clusterId;
short rightLabel = rightItem.clusterId;
if(leftLabel == 1 && rightLabel == 1) {
rightItem.clusterId = ++leftLabel;
instanceTable.put(rightItem);
} else if(leftLabel != 1 && rightLabel == 1) {
rightItem.clusterId = ++leftLabel;
instanceTable.put(rightItem);
} else if(leftLabel == 1 && rightLabel != 1) {
leftItem.clusterId = --rightLabel;
instanceTable.put(leftItem);
}else if(leftLabel != 1 && rightLabel != 1) {
if(rightLabel > (leftLabel + 1)) {
rightItem.clusterId = ++leftLabel;
instanceTable.put(rightItem);
}
}
}
}
private void updateRelation(RelationInstance instance) {
relationTable.update(instance.leftInstanceId, instance.id, instance.rightInstanceId);
}
private void removeRelation(RelationInstance instance) {
relationTable.removeRelation(instance.id);
}
public <K extends Comparable<K>> Result createIndex(String typeName, String attributeName, K dataType) {
Type type = typeTable.get(typeName, null);
if(type == null)
return new Result(false,"Type does not exists");
Query itemQuery = this.query();
List<Instance> instances = itemQuery.getInstances(type.id);
List<Attribute> attributes = type.getAllAttributes();
Attribute attribute = null;
List<Node<K>> nodes = new ArrayList<Node<K>>();
for(Attribute attr : attributes) {
if(attr.name.equals(attributeName)) {
attribute = attr; break;
}
}
if(attribute != null) {
if(attribute.repeating) {
for(Instance instance : instances) {
List<K> list = (List<K>) instance.getAttributeValue(attribute.name);
for(K key: list)
nodes.add(new Node<K>(key,instance.id));
}
}else{
for(Instance instance : instances) {
K key = (K) instance.getAttributeValue(attribute.name);
nodes.add(new Node<K>(key,instance.id));
}
}
closeQuery(itemQuery);
String fileName = IndexBuilder.getIndexFileName(type.id, attributeName);
if(IndexBuilder.createIndex(fileName, "rw", nodes))
return new Result(true, "Index created successfully");
}else {
return new Result(false, "Attribute not found");
}
return new Result(false, "Index creation failed");
}
public void addInstance(InstanceMetaItem item) {
instanceTable.put(item);
instanceDirtFlag= true;
}
public int addInstance(Instance instance, short clusterId) {
InstanceMetaItem metaItem = createInstaneMeta(instance);
metaItem.clusterId = clusterId;
return storeInstance(instance, metaItem);
}
private InstanceMetaItem createInstaneMeta(Instance instance) {
if(instance.id <=0) instance.id = ++instanceId;
InstanceMetaItem instanceItem = new InstanceMetaItem();
Type type = typeTable.get(instance.getClass().getSimpleName(), null);
instanceItem.typeId = type.id;
instanceItem.instanceId = instance.id;
instanceItem.instance = instance;
return instanceItem;
}
public Result dropIndex(Type type, String attributeName) {
String fileName = IndexBuilder.getIndexFileName(type.id, attributeName);
return new Result(IndexBuilder.dropIndex(fileName), "Index dropped successfully");
}
public Query query(){
try {
return new ItemQuery(ConceptNetDir, typeTable, instanceTable, relationTable);
}catch(IOException ie) {
ie.printStackTrace();
}
return null;
}
public Result commit() {
if(!readOnly) {
if(typeDirtFlag) {
if(!commitType().Success) {
return new Result(false,"Error in commiting the types");
}
generateCode();
typeList.clear();
typeDirtFlag = false;
}
if(instanceDirtFlag) {
if(!commitInstance().Success) {
return new Result(false,"Error in commiting the instances");
}
instanceDirtFlag = false;
}
}else{
return new Result(false, "Read-Only mode, cannot be commited");
}
return new Result(true,"Commit Success");
}
private Result commitType() {
try {
typeTable.commit();
properties.setProperty("TYPE_ID", String.valueOf(typeId));
PropertiesConfig.storeProperties(ConceptNetDir + ConStoreConstants.PROPERTIES_FILE,
properties);
return new Result(true);
}catch(IOException ie) {
log.log(Level.SEVERE, "Type Commit Exception", ie);
return new Result(false,"Type Commit Exception",ie);
}
}
private Result commitInstance() {
try {
instanceTable.commit();
relationTable.commit();
properties.setProperty("INSTANCE_ID", String.valueOf(instanceId));
PropertiesConfig.storeProperties(ConceptNetDir + ConStoreConstants.PROPERTIES_FILE,
properties);
return new Result(true);
}catch(IOException ie) {
log.log(Level.SEVERE, "Instance Commit Exception", ie);
return new Result(false,"Instance Commit Exception",ie);
}
}
private void generateCode(){
CodeGenerator cg = CodeGenerator.getInstance();
for(Type type: typeList) {
if(type instanceof Relation) {
Relation r = (Relation) type;
cg.generateCode(ConceptNetDir, r, typeTable.get(r.getLeftEntityId()).name,
typeTable.get(r.getRightEntityId()).name);
}
else {
cg.generateCode(ConceptNetDir, (Entity)type);
}
}
}
public void reInitializeNetFiles(String backupName) {
if(backupName == null)
backupName = new Long(System.currentTimeMillis()).toString();
File filePath = new File(ConceptNetDir + BAK);
if(!filePath.exists())
filePath.mkdirs();
String path = ConceptNetDir + BAK + backupName + "/";
FileUtil.createDir(path);
FileUtil.renameMove(ConceptNetDir + ConStoreConstants.NET_FILE,
path + ConStoreConstants.NET_FILE);
FileUtil.renameMove(ConceptNetDir + ConStoreConstants.INSTANCE_TABLE_FILE,
path + ConStoreConstants.INSTANCE_TABLE_FILE);
FileUtil.renameMove(ConceptNetDir + ConStoreConstants.NET_FSL_FILE,
path + ConStoreConstants.NET_FSL_FILE);
FileUtil.renameMove(ConceptNetDir + ConStoreConstants.RELATION_TABLE_FILE,
path + ConStoreConstants.RELATION_TABLE_FILE);
FileUtil.renameMove(ConceptNetDir + ConStoreConstants.RELATION_IDX_FILE,
path + ConStoreConstants.RELATION_IDX_FILE);
FileUtil.createFile(ConceptNetDir + ConStoreConstants.NET_FILE);
FileUtil.createFile(ConceptNetDir + ConStoreConstants.INSTANCE_TABLE_FILE);
FileUtil.createFile(ConceptNetDir + ConStoreConstants.RELATION_TABLE_FILE);
FileUtil.createFile(ConceptNetDir + ConStoreConstants.RELATION_IDX_FILE);
String fslFileName = ConceptNetDir + ConStoreConstants.NET_FSL_FILE;
FileUtil.createFile(fslFileName);
initializeFslFile(fslFileName);
}
public boolean close() {
if(!readOnly) {
try{
typeTable.close();
instanceTable.close();
relationTable.close();
TypeTableFactory.shutDown();
InstanceTableFactory.shutDown();
}catch(IOException ie){
log.log(Level.SEVERE, "ConceptNet file close exception", ie);
return false;
}
}
return true;
}
private void closeQuery(Query itemQuery) {
if(itemQuery != null) {
try{
itemQuery.close();
}catch(IOException ie){
log.log(Level.SEVERE, "Query files close exception", ie);
}
}
}
public void showStaistics() {
Query itemQuery = this.query();
long totalEntities = 0;
long totalRelations = 0;
System.out.println("IO_BUFFER_SIZE : " + ConStoreConstants.IO_BUFFER_SIZE);
System.out.println("QUERY_CACHE_SIZE : " + ConStoreConstants.QUERY_CACHE_SIZE);
System.out.println("INSTANCE_CACHE_SIZE : " + ConStoreConstants.INSTANCE_CACHE_SIZE);
for(Type t : typeTable.getAllItems()) {
if(t instanceof Entity) {
System.out.print("\nEntity : ");
System.out.print(t.id + " - ");
System.out.print(t.name);
int n = itemQuery.getEntityInstances(t.id).size();
System.out.print(" - " + n);
totalEntities += n;
} else if(t instanceof Relation) {
System.out.print("\nRelation: ");
System.out.print(t.id + " - ");
System.out.print(t.name);
int n = itemQuery.getRelationInstances(t.id).size();
System.out.print(" - " + n);
totalRelations += n;
}
}
System.out.println("\n******************************************");
System.out.println("No. of Types : " + typeTable.size());
System.out.println("No. of Entity Instances :" + totalEntities);
System.out.println("No. of Relation Instances :" + totalRelations);
System.out.println("No. of Instances :" + instanceTable.size());
closeQuery(itemQuery);
}
public final static String BAK = "bak/";
}