/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package org.teiid.dqp.internal.process;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.teiid.adminapi.impl.VDBMetaData;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidProcessingException;
import org.teiid.metadata.AbstractMetadataRecord;
import org.teiid.metadata.AbstractMetadataRecord.DataModifiable;
import org.teiid.metadata.AbstractMetadataRecord.Modifiable;
import org.teiid.metadata.Schema;
import org.teiid.query.metadata.TempMetadataID;
import org.teiid.query.metadata.TransformationMetadata;
import org.teiid.query.optimizer.relational.RelationalPlanner;
import org.teiid.query.tempdata.GlobalTableStore;
import org.teiid.query.util.CommandContext;
/**
* Tracks what views were used and what tables are accessed
*/
public class AccessInfo implements Serializable {
private static final long serialVersionUID = -2608267960584191359L;
private transient Set<Object> objectsAccessed;
private boolean sensitiveToMetadataChanges = true;
private List<List<String>> externalNames;
private long creationTime = System.currentTimeMillis();
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
externalNames = initExternalList(externalNames, objectsAccessed);
out.defaultWriteObject();
}
public boolean isSensitiveToMetadataChanges() {
return sensitiveToMetadataChanges;
}
public void setSensitiveToMetadataChanges(boolean sensitiveToMetadataChanges) {
this.sensitiveToMetadataChanges = sensitiveToMetadataChanges;
}
private static List<List<String>> initExternalList(List<List<String>> externalNames, Set<? extends Object> accessed) {
if (externalNames == null) {
externalNames = new ArrayList<List<String>>(accessed.size());
for (Object object : accessed) {
if (object instanceof AbstractMetadataRecord) {
AbstractMetadataRecord t = (AbstractMetadataRecord)object;
externalNames.add(Arrays.asList(t.getParent().getName(), t.getName()));
} else if (object instanceof TempMetadataID) {
TempMetadataID t = (TempMetadataID)object;
externalNames.add(Arrays.asList(t.getID()));
}
}
}
return externalNames;
}
public void addAccessedObject(Object id) {
if (this.objectsAccessed == null) {
this.objectsAccessed = new HashSet<Object>();
}
this.objectsAccessed.add(id);
}
public Set<Object> getObjectsAccessed() {
return objectsAccessed;
}
public long getCreationTime() {
return creationTime;
}
void populate(CommandContext context, boolean data) {
Set<Object> objects = null;
if (data) {
objects = context.getDataObjects();
} else {
objects = context.getPlanningObjects();
}
if (objects == null || objects.isEmpty()) {
this.objectsAccessed = Collections.emptySet();
} else {
this.objectsAccessed = objects;
}
}
/**
* Restore reconnects to the live metadata objects
* @throws TeiidComponentException
* @throws TeiidProcessingException
*/
void restore() throws TeiidComponentException, TeiidProcessingException {
if (this.objectsAccessed != null) {
return;
}
VDBMetaData vdb = DQPWorkContext.getWorkContext().getVDB();
TransformationMetadata tm = vdb.getAttachment(TransformationMetadata.class);
GlobalTableStore globalStore = vdb.getAttachment(GlobalTableStore.class);
if (!externalNames.isEmpty()) {
this.objectsAccessed = new HashSet<Object>(externalNames.size());
for (List<String> key : this.externalNames) {
if (key.size() == 1) {
String matTableName = key.get(0);
TempMetadataID id = globalStore.getGlobalTempTableMetadataId(matTableName);
if (id == null) {
//if the id is null, then create a local instance
String viewFullName = matTableName.substring(RelationalPlanner.MAT_PREFIX.length());
id = globalStore.getGlobalTempTableMetadataId(tm.getGroupID(viewFullName));
}
this.objectsAccessed.add(id);
} else {
Schema s = tm.getMetadataStore().getSchema(key.get(0));
Modifiable m = s.getTables().get(key.get(1));
if (m == null) {
m = s.getProcedures().get(key.get(1));
}
if (m != null) {
this.objectsAccessed.add(m);
}
}
}
} else {
this.objectsAccessed = Collections.emptySet();
}
this.externalNames = null;
}
boolean validate(boolean data, long modTime) {
if (this.objectsAccessed == null || modTime < 0) {
return true;
}
for (Object o : this.objectsAccessed) {
if (!data) {
if (o instanceof Modifiable) {
Modifiable m = (Modifiable)o;
if (m.getLastModified() < 0) {
return false; //invalid object
}
if (sensitiveToMetadataChanges && m.getLastModified() - modTime >= this.creationTime) {
return false;
}
}
} else if (o instanceof DataModifiable && ((DataModifiable)o).getLastDataModification() - modTime >= this.creationTime) {
return false;
}
}
return true;
}
}