/*
* 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 2006 - 2013 Pentaho Corporation. All rights reserved.
*/
package org.pentaho.platform.uifoundation.component.xml;
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;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
@SuppressWarnings( "rawtypes" )
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() ) {
String vis = (String) model.getProperty( "visible" );
if ( vis != null ) {
String[] visibleContexts = vis.split( "," );
boolean visibleToContext = false;
for ( String context : visibleContexts ) {
if ( "adhoc".equals( context.trim() ) ) {
visibleToContext = true;
break;
}
}
if ( !visibleToContext ) {
continue;
}
}
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;
}
@SuppressWarnings( "deprecation" )
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;
}
}