/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License, version 2 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* 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.
*
* Copyright 2007 - 2008 Pentaho Corporation. All rights reserved.
*
*/
package org.pentaho.platform.uifoundation.component.xml;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.pentaho.commons.connection.IPentahoResultSet;
import org.pentaho.metadata.model.Category;
import org.pentaho.metadata.model.Domain;
import org.pentaho.metadata.model.LogicalColumn;
import org.pentaho.metadata.model.LogicalModel;
import org.pentaho.metadata.model.concept.types.DataType;
import org.pentaho.metadata.model.concept.types.LocalizedString;
import org.pentaho.metadata.repository.IMetadataDomainRepository;
import org.pentaho.platform.api.engine.IParameterProvider;
import org.pentaho.platform.api.engine.IPentahoUrlFactory;
import org.pentaho.platform.api.engine.IRuntimeContext;
import org.pentaho.platform.engine.core.solution.SimpleParameterProvider;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.engine.services.solution.SolutionHelper;
import org.pentaho.platform.uifoundation.messages.Messages;
import org.pentaho.platform.util.messages.LocaleHelper;
public class PMDUIComponent extends XmlComponent {
private static final long serialVersionUID = -911457505257919399L;
private static final Log logger = LogFactory.getLog(PMDUIComponent.class);
public static final int ACTION_LIST_DOMAINS = 1;
public static final int ACTION_LIST_MODELS = 2;
public static final int ACTION_MODELS_DETAIL = 3;
public static final int ACTION_LOAD_MODEL = 4;
public static final int ACTION_LOOKUP = 5;
private int action;
private String domainName;
private String modelId;
private String columnId;
private IParameterProvider parameters;
public PMDUIComponent(final IPentahoUrlFactory urlFactory, final List messages) {
super(urlFactory, messages, ""); //$NON-NLS-1$
}
@Override
public Log getLogger() {
return PMDUIComponent.logger;
}
@Override
public boolean validate() {
return true;
}
public IMetadataDomainRepository getMetadataRepository() {
return PentahoSystem.get(IMetadataDomainRepository.class, getSession());
}
@Override
public Document getXmlContent() {
if (action == PMDUIComponent.ACTION_LIST_MODELS) {
return listModels();
} else if (action == PMDUIComponent.ACTION_LOAD_MODEL) {
return loadModel();
} else if (action == PMDUIComponent.ACTION_LOOKUP) {
return getLookup();
} else {
throw new RuntimeException(Messages.getInstance().getErrorString(
"PMDUIComponent.ERROR_0002_ILLEGAL_ACTION", String.valueOf(action))); //$NON-NLS-1$
}
}
private Document listModels() {
// Create a document that describes the result
Document doc = DocumentHelper.createDocument();
Element root = doc.addElement("metadata"); //$NON-NLS-1$
Element modelsNode = root.addElement("models"); //$NON-NLS-1$
if (domainName == null) {
try {
for (String domain : getMetadataRepository().getDomainIds()) {
addThinDomainModels(domain, modelsNode, root);
}
} catch (Throwable t) {
error(Messages.getInstance().getString("PMDUIComponent.ERROR_0001_GET_MODEL_LIST")); //$NON-NLS-1$
t.printStackTrace();
root.addElement("message").setText(Messages.getInstance().getString("PMDUIComponent.USER_NO_DOMAIN_SPECIFIED")); //$NON-NLS-1$ //$NON-NLS-2$
}
} else {
addThinDomainModels(domainName, modelsNode, root);
}
return doc;
}
private void addThinDomainModels(final String domain, final Element modelsNode, final Element root) {
IMetadataDomainRepository repo = getMetadataRepository();
Domain domainObject = repo.getDomain(domain);
String locale = LocaleHelper.getClosestLocale(LocaleHelper.getLocale().toString(), domainObject.getLocaleCodes());
Element modelNode;
for (LogicalModel model : domainObject.getLogicalModels()) {
modelNode = modelsNode.addElement("model"); //$NON-NLS-1$
modelNode.addElement("domain_id").setText(domain); //$NON-NLS-1$
if (model.getId() != null) {
modelNode.addElement("model_id").setText(model.getId()); //$NON-NLS-1$
}
String modelName = model.getName(locale);
if (modelName != null) {
modelNode.addElement("model_name").setText(modelName); //$NON-NLS-1$
}
if (model.getDescription() != null) {
String modelDescription = model.getDescription(locale);
if (modelDescription != null) {
modelNode.addElement("model_description").setText(modelDescription); //$NON-NLS-1$
}
}
}
return;
}
private Document loadModel() {
// Create a document that describes the result
Document doc = DocumentHelper.createDocument();
Element root = doc.addElement("metadata"); //$NON-NLS-1$
if (domainName == null) {
// we can't do this without a model
root.addElement("message").setText(Messages.getInstance().getString("PMDUIComponent.USER_NO_DOMAIN_SPECIFIED")); //$NON-NLS-1$ //$NON-NLS-2$
return doc;
}
if (modelId == null) {
// we can't do this without a model
root.addElement("message").setText(Messages.getInstance().getString("PMDUIComponent.USER_NO_MODEL_SPECIFIED")); //$NON-NLS-1$ //$NON-NLS-2$
return doc;
}
Element modelNode = root.addElement("model"); //$NON-NLS-1$
// because it's lighter weight, check the thin model
Domain domain = getMetadataRepository().getDomain(domainName);
if (domain == null) {
root.addElement("message").setText(Messages.getInstance().getString("PMDUIComponent.USER_DOMAIN_LOADING_ERROR", domainName)); //$NON-NLS-1$ //$NON-NLS-2$
return doc;
}
String locale = LocaleHelper.getClosestLocale(LocaleHelper.getLocale().toString(), domain.getLocaleCodes());
LogicalModel model = domain.findLogicalModel(modelId);
if (model == null) {
root.addElement("message").setText(Messages.getInstance().getString("PMDUIComponent.USER_MODEL_LOADING_ERROR", modelId)); //$NON-NLS-1$ //$NON-NLS-2$
error(Messages.getInstance().getString("PMDUIComponent.USER_MODEL_LOADING_ERROR", modelId)); //$NON-NLS-1$
return doc;
}
modelNode.addElement("domain_id").setText(domainName); //$NON-NLS-1$
if (model.getId() != null) {
modelNode.addElement("model_id").setText(model.getId()); //$NON-NLS-1$
}
if (model.getName(locale) != null) {
modelNode.addElement("model_name").setText(model.getName(locale)); //$NON-NLS-1$
}
if (model.getDescription(locale) != null) {
modelNode.addElement("model_description").setText(model.getDescription(locale)); //$NON-NLS-1$
}
Element tableNode;
for (Category category : model.getCategories()) {
tableNode = modelNode.addElement("view"); //$NON-NLS-1$
if (category.getId() != null) {
tableNode.addElement("view_id").setText(category.getId()); //$NON-NLS-1$
}
if (category.getName(locale) != null) {
tableNode.addElement("view_name").setText(category.getName(locale)); //$NON-NLS-1$
}
if (category.getDescription(locale) != null) {
tableNode.addElement("view_description").setText(category.getDescription(locale)); //$NON-NLS-1$
}
for (LogicalColumn column : category.getLogicalColumns()) {
Boolean hidden = (Boolean)column.getProperty("hidden"); //$NON-NLS-1$
if (hidden != null && hidden) {
continue;
}
addColumn(column, tableNode, locale);
}
}
return doc;
}
public void addColumn(final LogicalColumn column, final Element tableNode, final String locale) {
Element columnNode = tableNode.addElement("column"); //$NON-NLS-1$
if (column.getId() != null) {
columnNode.addElement("column_id").setText(column.getId()); //$NON-NLS-1$
}
if (column.getName(locale) != null) {
columnNode.addElement("column_name").setText(column.getName(locale)); //$NON-NLS-1$
}
if (column.getDescription(locale) != null) {
columnNode.addElement("column_description").setText(column.getDescription(locale)); //$NON-NLS-1$
}
if (column.getFieldType() != null) {
// TODO this should take a locale
String desc = column.getFieldType().getDescription();
desc = org.pentaho.pms.messages.Messages.getString(desc);
columnNode.addElement("column_field_type").setText(desc); //$NON-NLS-1$
}
DataType dataType = column.getDataType();
if (dataType != null) {
columnNode.addElement("column_type").setText(dataType.getName()); //$NON-NLS-1$
}
if (column.getProperty("lookup") != null) { //$NON-NLS-1$
columnNode.addElement("column_lookup").setText("true"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
public Document getLookup() {
// Create a document that describes the result
Document doc = DocumentHelper.createDocument();
Element root = doc.addElement("metadata"); //$NON-NLS-1$
if (domainName == null) {
// we can't do this without a model
root.addElement("message").setText(Messages.getInstance().getString("PMDUIComponent.USER_NO_DOMAIN_SPECIFIED")); //$NON-NLS-1$ //$NON-NLS-2$
return doc;
}
if (modelId == null) {
// we can't do this without a view
root.addElement("message").setText(Messages.getInstance().getString("PMDUIComponent.USER_NO_MODEL_SPECIFIED")); //$NON-NLS-1$ //$NON-NLS-2$
return doc;
}
if (columnId == null) {
// we can't do this without a view
root.addElement("message").setText(Messages.getInstance().getString("PMDUIComponent.USER_NO_COLUMN_SPECIFIED")); //$NON-NLS-1$ //$NON-NLS-2$
return doc;
}
Domain domain = getMetadataRepository().getDomain(domainName);
String locale = LocaleHelper.getClosestLocale(LocaleHelper.getLocale().toString(), domain.getLocaleCodes());
LogicalModel model = domain.findLogicalModel(modelId); // This is the business view that was selected.
if (model == null) {
root.addElement("message").setText(Messages.getInstance().getString("PMDUIComponent.USER_MODEL_LOADING_ERROR", modelId)); //$NON-NLS-1$ //$NON-NLS-2$
return doc;
}
LogicalColumn column = model.findLogicalColumn(columnId);
if (column == null) {
root.addElement("message").setText(Messages.getInstance().getString("PMDUIComponent.USER_COLUMN_NOT_FOUND")); //$NON-NLS-1$ //$NON-NLS-2$
return doc;
}
// Temporary hack to get the BusinessCategory. When fixed properly, you should be able to interrogate the
// business column thingie for it's containing BusinessCategory.
Category view = null;
for (Category category : model.getCategories()) {
for (LogicalColumn col : category.getLogicalColumns()) {
if (col.getId().equals(column.getId())) {
view = category;
break;
}
}
}
if (view == null) {
root.addElement("message").setText(Messages.getInstance().getString("PMDUIComponent.USER_VIEW_NOT_FOUND")); //$NON-NLS-1$ //$NON-NLS-2$
return doc;
}
String mql = "<mql><domain_type>relational</domain_type><domain_id>" + domainName + "</domain_id><model_id>" + modelId + "</model_id>"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
if (column.getProperty("lookup") == null) { //$NON-NLS-1$
mql += "<selection><view>" + view.getId() + "</view><column>" + column.getId() + "</column></selection>"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
mql += "<orders><order><direction>asc</direction><view_id>" + view.getId() + "</view_id><column_id>" + column.getId() + "</column_id></order></orders>"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
} else {
String lookup = (String)column.getProperty("lookup"); //$NON-NLS-1$
// assume model and view are the same...
StringTokenizer tokenizer1 = new StringTokenizer(lookup, ";"); //$NON-NLS-1$
while (tokenizer1.hasMoreTokens()) {
StringTokenizer tokenizer2 = new StringTokenizer(tokenizer1.nextToken(), "."); //$NON-NLS-1$
if (tokenizer2.countTokens() == 2) {
String lookupViewId = tokenizer2.nextToken();
String lookupColumnId = tokenizer2.nextToken();
mql += "<selection><view>" + lookupViewId + "</view><column>" + lookupColumnId + "</column></selection>"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
}
mql += "</mql>"; //$NON-NLS-1$
ArrayList messages = new ArrayList();
SimpleParameterProvider lookupParameters = new SimpleParameterProvider();
lookupParameters.setParameter("mql", mql); //$NON-NLS-1$
IRuntimeContext runtime = SolutionHelper.doAction(
"system", "metadata", "PickList.xaction", "lookup-list", lookupParameters, getSession(), messages, this); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
IPentahoResultSet results = null;
if (runtime != null) {
if (runtime.getStatus() == IRuntimeContext.RUNTIME_STATUS_SUCCESS) {
if (runtime.getOutputNames().contains("data")) { //$NON-NLS-1$
results = runtime.getOutputParameter("data").getValueAsResultSet(); //$NON-NLS-1$
Object[][] columnHeaders = results.getMetaData().getColumnHeaders();
boolean hasColumnHeaders = columnHeaders != null;
Element rowElement;
Element dataElement = root.addElement("data"); //$NON-NLS-1$
if (hasColumnHeaders) {
for (int rowNo = 0; rowNo < columnHeaders.length; rowNo++) {
rowElement = dataElement.addElement("COLUMN-HDR-ROW"); //$NON-NLS-1$
for (int columnNo = 0; columnNo < columnHeaders[rowNo].length; columnNo++) {
Object nameAttr = results.getMetaData().getAttribute(rowNo, columnNo, "name"); //$NON-NLS-1$
if ((nameAttr != null) && (nameAttr instanceof LocalizedString)) {
LocalizedString str = (LocalizedString) nameAttr;
String name = str.getLocalizedString(locale);
if (name != null) {
rowElement.addElement("COLUMN-HDR-ITEM").setText(name); //$NON-NLS-1$
} else {
rowElement.addElement("COLUMN-HDR-ITEM").setText(columnHeaders[rowNo][columnNo].toString()); //$NON-NLS-1$
}
} else {
rowElement.addElement("COLUMN-HDR-ITEM").setText(columnHeaders[rowNo][columnNo].toString()); //$NON-NLS-1$
}
}
}
}
Object row[] = results.next();
while (row != null) {
rowElement = dataElement.addElement("DATA-ROW"); //$NON-NLS-1$
for (Object element : row) {
if (element == null) {
rowElement.addElement("DATA-ITEM").setText(""); //$NON-NLS-1$ //$NON-NLS-2$
} else {
rowElement.addElement("DATA-ITEM").setText(element.toString()); //$NON-NLS-1$
}
}
row = results.next();
}
}
}
}
return doc;
}
public void setAction(final int action) {
this.action = action;
}
public int getAction() {
return action;
}
public void setDomainName(final String domainName) {
this.domainName = domainName;
}
public String getDomainName() {
return domainName;
}
public IParameterProvider getParameters() {
return parameters;
}
public void setParameters(final IParameterProvider parameters) {
this.parameters = parameters;
}
public String getModelId() {
return modelId;
}
public void setModelId(final String modelId) {
this.modelId = modelId;
}
public String getColumnId() {
return columnId;
}
public void setColumnId(final String columnId) {
this.columnId = columnId;
}
}