/*
* 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.olingo.service;
import java.net.URI;
import java.net.URISyntaxException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ServiceMetadata;
import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.UriParameter;
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
import org.apache.olingo.server.api.uri.UriResourceNavigation;
import org.apache.olingo.server.core.RequestURLHierarchyVisitor;
import org.apache.olingo.server.core.uri.parser.UriParserException;
import org.apache.olingo.server.core.uri.validator.UriValidationException;
import org.teiid.core.TeiidException;
import org.teiid.metadata.Column;
import org.teiid.metadata.ForeignKey;
import org.teiid.metadata.MetadataStore;
import org.teiid.metadata.Table;
import org.teiid.odata.api.SQLParameter;
import org.teiid.olingo.common.ODataTypeManager;
import org.teiid.query.sql.lang.Criteria;
import org.teiid.query.sql.lang.Update;
import org.teiid.query.sql.symbol.Constant;
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.GroupSymbol;
import org.teiid.query.sql.symbol.Reference;
public class ReferenceUpdateSQLBuilder extends RequestURLHierarchyVisitor {
private final MetadataStore metadata;
private String baseURI;
private ServiceMetadata serviceMetadata;
private OData odata;
private ScopedTable updateTable;
private ScopedTable referenceTable;
private boolean collection;
private final ArrayList<SQLParameter> params = new ArrayList<SQLParameter>();
static class ScopedTable extends DocumentNode {
private ForeignKey fk;
public ScopedTable (Table table, EdmEntityType type, List<UriParameter> keys) {
setTable(table);
setEdmEntityType(type);
setGroupSymbol(new GroupSymbol(table.getFullName()));
setKeyPredicates(keys);
}
public ForeignKey getFk() {
return fk;
}
public void setFk(ForeignKey fk) {
this.fk = fk;
}
}
public ReferenceUpdateSQLBuilder(MetadataStore metadata, String baseURI,
ServiceMetadata serviceMetadata, OData odata) {
this.metadata = metadata;
this.baseURI = baseURI;
this.serviceMetadata = serviceMetadata;
this.odata = odata;
}
@Override
public void visit(UriResourceEntitySet info) {
Table table = DocumentNode.findTable(info.getEntitySet(), this.metadata);
EdmEntityType type = info.getEntitySet().getEntityType();
List<UriParameter> keys = info.getKeyPredicates();
this.updateTable = new ScopedTable(table, type, keys);
}
@Override
public void visit(UriResourceNavigation info) {
EdmNavigationProperty property = info.getProperty();
this.referenceTable = new ScopedTable(DocumentNode.findTable(property.getType(),
this.metadata), property.getType(),
info.getKeyPredicates());
if (property.isCollection()) {
ForeignKey fk = DocumentNode.joinFK(referenceTable, this.updateTable, property);
referenceTable.setFk(fk);
ScopedTable temp = this.updateTable;
this.updateTable = referenceTable;
this.referenceTable = temp;
this.collection = true;
}
else {
ForeignKey fk = DocumentNode.joinFK(this.updateTable, referenceTable, property);
this.updateTable.setFk(fk);
}
}
public Update updateReference(URI referenceId, boolean prepared, boolean delete) throws SQLException {
try {
if (referenceId != null) {
UriInfo uriInfo = ODataSQLBuilder.buildUriInfo(referenceId, this.baseURI, this.serviceMetadata, this.odata);
UriResourceEntitySet uriEnitytSet = (UriResourceEntitySet)uriInfo.asUriInfoResource().getUriResourceParts().get(0);
if (this.collection) {
this.updateTable.setKeyPredicates(uriEnitytSet.getKeyPredicates());
}
else {
this.referenceTable.setKeyPredicates(uriEnitytSet.getKeyPredicates());
}
}
} catch (UriParserException e) {
throw new SQLException(e);
} catch (URISyntaxException e) {
throw new SQLException(e);
} catch (UriValidationException e) {
throw new SQLException(e);
}
try {
Update update = new Update();
update.setGroup(this.updateTable.getGroupSymbol());
List<String> columnNames = DocumentNode.getColumnNames(this.updateTable.getFk().getColumns());
for (int i = 0; i < columnNames.size(); i++) {
Column column = this.updateTable.getFk().getColumns().get(i);
String columnName = columnNames.get(i);
ElementSymbol symbol = new ElementSymbol(columnName, this.updateTable.getGroupSymbol());
EdmEntityType entityType = this.updateTable.getEdmEntityType();
EdmProperty edmProperty = (EdmProperty)entityType.getProperty(columnName);
// reference table keys will be null for delete scenario
Object value = null;
if (!delete) {
UriParameter parameter = getParameter(this.updateTable.getFk().getReferenceColumns().get(i),
this.referenceTable.getKeyPredicates());
value = ODataTypeManager.parseLiteral(edmProperty, column.getJavaType(), parameter.getText());
}
if (prepared) {
update.addChange(symbol, new Reference(i++));
this.params.add(ODataSQLBuilder.asParam(edmProperty, value));
}
else {
update.addChange(symbol, new Constant(ODataSQLBuilder.asParam(edmProperty, value).getValue()));
}
}
Criteria criteria = DocumentNode.buildEntityKeyCriteria(
this.updateTable, null, this.metadata, this.odata, null, null);
update.setCriteria(criteria);
return update;
} catch (TeiidException e) {
throw new SQLException(e);
}
}
private UriParameter getParameter(String name, List<UriParameter> keys) {
for (UriParameter parameter:keys) {
String propertyName = parameter.getName();
if (propertyName.equals(name)) {
return parameter;
}
}
return null;
}
public List<SQLParameter> getParameters(){
return this.params;
}
}