/*
* This software 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 3 of the License, or
* (at your option) any later version.
*
* This software 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 software. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2011 De Bortoli Wines Pty Limited (Australia)
*/
package org.pentaho.di.openerp.core;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collections;
import org.apache.xmlrpc.XmlRpcException;
import org.pentaho.di.core.database.DatabaseFactoryInterface;
import org.pentaho.di.core.database.DatabaseMeta;
import org.pentaho.di.core.row.ValueMetaInterface;
import com.debortoliwines.openerp.api.FilterCollection;
import com.debortoliwines.openerp.api.ObjectAdapter;
import com.debortoliwines.openerp.api.OpenERPCommand;
import com.debortoliwines.openerp.api.OpeneERPApiException;
import com.debortoliwines.openerp.api.Session;
import com.debortoliwines.openerp.api.Field;
import com.debortoliwines.openerp.api.FieldCollection;
import com.debortoliwines.openerp.api.RowCollection;
import com.debortoliwines.openerp.api.Field.FieldType;
/**
* Helper class to keep common functionality in one class
*
* @author Pieter van der Merwe
*/
public class OpenERPHelper implements DatabaseFactoryInterface {
private Session openERPConnection;
private OpenERPCommand commands;
private boolean importReturnsIDS = false;
@Override
public String getConnectionTestReport( DatabaseMeta databaseMeta ) {
try {
OpenERPHelper helper = new OpenERPHelper( databaseMeta );
helper.StartSession();
return "Successfully connected to [" + databaseMeta.environmentSubstitute( databaseMeta.getName() ) + "]";
} catch ( NumberFormatException e ) {
return "Invalid port number: " + e.getMessage();
} catch ( Exception e ) {
return "Connection failed: " + e.getMessage();
}
}
// / Need a default constructor for the "Test" button to work on the connect database dialog
public OpenERPHelper() {
}
public OpenERPHelper( DatabaseMeta databaseMeta ) {
openERPConnection =
new Session( databaseMeta.environmentSubstitute( databaseMeta.getHostname() ), Integer.parseInt( databaseMeta
.environmentSubstitute( databaseMeta.getDatabasePortNumberString() ) ), databaseMeta
.environmentSubstitute( databaseMeta.getDatabaseName() ), databaseMeta.environmentSubstitute( databaseMeta
.getUsername() ), databaseMeta.environmentSubstitute( databaseMeta.getPassword() ) );
}
public void StartSession() throws Exception {
openERPConnection.startSession();
commands = openERPConnection.getOpenERPCommand();
// Don't automatically filter out active items in any steps
openERPConnection.getContext().setActiveTest( false );
try {
importReturnsIDS = openERPConnection.getServerVersion().getMajor() >= 7;
} catch ( XmlRpcException e ) {
// Play it safe
importReturnsIDS = false;
}
}
public String[] getModelList() {
String[] modelNames = new String[0];
try {
ObjectAdapter modelAdapter = new ObjectAdapter( openERPConnection, "ir.model" );
RowCollection rows = modelAdapter.searchAndReadObject( null, new String[]{ "model" } );
modelNames = new String[rows.size()];
for ( int i = 0; i < modelNames.length; i++ ) {
modelNames[i] = rows.get( i ).get( "model" ).toString();
}
//CHECKSTYLE:EmptyBlock:OFF
} catch ( Exception e ) {
}
return modelNames;
}
public int getModelDataCount( String model, FilterCollection filter ) throws XmlRpcException, OpeneERPApiException {
ObjectAdapter modelAdapter = new ObjectAdapter( openERPConnection, model );
return modelAdapter.getObjectCount( filter );
}
public RowCollection getModelData( String model, FilterCollection filter, ArrayList<FieldMapping> mappings,
int offset, int limit ) throws XmlRpcException, OpeneERPApiException {
ArrayList<String> fieldList = new ArrayList<String>();
for ( FieldMapping map : mappings ) {
if ( !fieldList.contains( map.source_field ) ) {
fieldList.add( map.source_field );
}
}
String[] fieldStringList = new String[fieldList.size()];
fieldStringList = fieldList.toArray( fieldStringList );
ObjectAdapter modelAdapter = new ObjectAdapter( openERPConnection, model );
return modelAdapter.searchAndReadObject( filter, fieldStringList, offset, limit, null );
}
public RowCollection getModelData( String model, FilterCollection filter, String[] fieldStringList )
throws XmlRpcException, OpeneERPApiException {
ObjectAdapter modelAdapter = new ObjectAdapter( openERPConnection, model );
return modelAdapter.searchAndReadObject( filter, fieldStringList );
}
public String[] getOutputFields( String model ) throws MalformedURLException, XmlRpcException, OpeneERPApiException {
ObjectAdapter modelAdapter = new ObjectAdapter( openERPConnection, model );
FieldCollection fields = modelAdapter.getFields();
ArrayList<String> fieldArray = new ArrayList<String>();
for ( Field field : fields ) {
boolean readonly = field.getReadonly();
// See if any of the states allows the readonly property to be false
// If so, then we need to display the field as rows could potentially be in a
// state that allows readonly to be false
if ( readonly == true ) {
for ( Object[] stateProperty : field.getStateProperties( "readonly" ) ) {
boolean stateReadonly =
( (Boolean) ( stateProperty[1] instanceof Integer ? (Integer) stateProperty[1] == 1 : stateProperty[1] ) );
readonly = readonly && stateReadonly;
if ( readonly == false ) {
break;
}
}
}
if ( field.getType() == FieldType.ONE2MANY || readonly == true ) {
continue;
}
fieldArray.add( field.getName() );
}
// Sort the fields alphabetically
Collections.sort( fieldArray );
return fieldArray.toArray( new String[fieldArray.size()] );
}
public ObjectAdapter getAdapter( String objectName ) throws XmlRpcException, OpeneERPApiException {
return openERPConnection.getObjectAdapter( objectName );
}
public void deleteObjects( String model, ArrayList<Object> ids ) throws XmlRpcException {
commands.unlinkObject( model, ids.toArray( new Object[ids.size()] ) );
}
public boolean getImportReturnIDS() {
return importReturnsIDS;
}
public ArrayList<FieldMapping> getDefaultFieldMappings( String model ) throws Exception {
ArrayList<FieldMapping> mappings = new ArrayList<FieldMapping>();
ObjectAdapter adapter = new ObjectAdapter( openERPConnection, model );
FieldCollection fields = adapter.getFields();
FieldMapping fieldMap = new FieldMapping();
fieldMap.source_model = model;
fieldMap.source_field = "id";
fieldMap.source_index = -1;
fieldMap.target_model = model;
fieldMap.target_field = "id";
fieldMap.target_field_label = "Database ID";
fieldMap.target_field_type = ValueMetaInterface.TYPE_INTEGER;
mappings.add( fieldMap );
for ( Field field : fields ) {
fieldMap = new FieldMapping();
String fieldName = field.getName();
fieldMap.source_model = model;
fieldMap.source_field = fieldName;
fieldMap.source_index = -1;
fieldMap.target_model = model;
fieldMap.target_field = fieldName;
fieldMap.target_field_label = field.getDescription();
Field.FieldType fieldType = field.getType();
switch ( fieldType ) {
case CHAR:
case TEXT:
case BINARY: // Binaries are base64 encoded strings
fieldMap.target_field_type = ValueMetaInterface.TYPE_STRING;
mappings.add( fieldMap );
break;
case BOOLEAN:
fieldMap.target_field_type = ValueMetaInterface.TYPE_BOOLEAN;
mappings.add( fieldMap );
break;
case FLOAT:
fieldMap.target_field_type = ValueMetaInterface.TYPE_NUMBER;
mappings.add( fieldMap );
break;
case DATETIME:
case DATE:
fieldMap.target_field_type = ValueMetaInterface.TYPE_DATE;
mappings.add( fieldMap );
break;
case MANY2ONE:
FieldMapping newFieldMap = fieldMap.Clone();
// Normal id field
newFieldMap.source_index = 0;
newFieldMap.target_model = field.getRelation();
newFieldMap.target_field = fieldName + "_id";
newFieldMap.target_field_label = field.getDescription() + "/Id";
newFieldMap.target_field_type = ValueMetaInterface.TYPE_INTEGER;
mappings.add( newFieldMap );
// Add name field
newFieldMap = fieldMap.Clone();
newFieldMap.source_index = 1;
newFieldMap.target_model = field.getRelation();
newFieldMap.target_field = fieldName + "_name";
newFieldMap.target_field_label = field.getDescription() + "/Name";
newFieldMap.target_field_type = ValueMetaInterface.TYPE_STRING;
mappings.add( newFieldMap );
break;
case ONE2MANY:
case MANY2MANY:
default:
fieldMap.target_field_type = ValueMetaInterface.TYPE_STRING;
mappings.add( fieldMap );
break;
}
}
return mappings;
}
}