Switching A DataSource Based On A User

0

Hello again,

I've following this "tutorial" for creating a dynamic datasource switch.

I want to use one report, but each client have their own datasource.

http://community.jaspersoft.com/wiki/switching-datasource-based-user

I'm using JasperServer 5.5.0 with the installer and iReport 5.5.0 with the installer

So, after many searches, finally I got working the jar, but when I run the report on the jasperserver web admin.

I got the java.lang.NullPointerException

I'm going to attach the files and a screenshot of the error, and, at the bottom the source code.

 

Thanks for your help!

Best regards!

JasperServerCustomDataSource.java

package com.jasperserver.custom.datasource;
 
 
import java.util.Map;
import java.sql.SQLException;
 
 
import net.sf.jasperreports.engine.JRParameter;
 
 
import org.springframework.context.i18n.LocaleContextHolder;
 
 
import com.jaspersoft.jasperserver.api.metadata.jasperreports.domain.ReportDataSource;
import com.jaspersoft.jasperserver.api.metadata.jasperreports.service.ReportDataSourceService;
import com.jaspersoft.jasperserver.api.common.domain.ExecutionContext;
import com.jaspersoft.jasperserver.api.common.service.BeanForInterfaceImplementationFactory;
import com.jaspersoft.jasperserver.api.engine.jasperreports.service.impl.JdbcDataSourceService;
import com.jaspersoft.jasperserver.api.engine.jasperreports.service.impl.JdbcReportDataSourceServiceFactory;
//import com.jaspersoft.jasperserver.api.engine.jasperreports.util.DataSourceServiceFactory;
import com.jaspersoft.jasperserver.war.common.JasperServerUtil;
 
 
import com.jaspersoft.jasperserver.api.metadata.common.service.RepositoryService;
 
 
public class JasperServerCustomDataSource implements ReportDataSourceService {
private JdbcDataSourceService connection;
private RepositoryService repositoryService;
private BeanForInterfaceImplementationFactory dataSourceServiceFactory;
//private DataSourceServiceFactory dataSourceServiceFactory;
 
public JasperServerCustomDataSource(RepositoryService repositoryService, BeanForInterfaceImplementationFactory dsServiceFactory) {
  super();
  this.repositoryService = repositoryService;
  this.dataSourceServiceFactory = dsServiceFactory;
}
 
 
@SuppressWarnings({ "unchecked", "rawtypes" })
public void setReportParameterValues(Map parametersValue) {
  String ds_name = (String) parametersValue.get("jasper_ds_name");
 
  if( (ds_name == null) || (ds_name.isEmpty()) ) {
   ds_name = "CUSTOMER_DS1";
  }
 
  String ds_uri = "/datasources/" + ds_name;
 
 
  connection = getRepositoryDatasource(ds_uri);
 
 
  try {
   parametersValue.put(JRParameter.REPORT_CONNECTION, connection
     .getDataSource().getConnection());
  } catch (SQLException e) {
   e.printStackTrace();
  }
}
 
 
public JdbcDataSourceService getRepositoryDatasource(String repositoryURI) {
  ExecutionContext context = JasperServerUtil
    .getExecutionContext(LocaleContextHolder.getLocale());
 
 
  ReportDataSource datasource = (ReportDataSource) repositoryService
    .getResource(context, repositoryURI);
 
 
  JdbcReportDataSourceServiceFactory factory = (JdbcReportDataSourceServiceFactory) dataSourceServiceFactory
    .getBean(datasource.getClass());
 
 
  JdbcDataSourceService DSservice = (JdbcDataSourceService) factory
    .createService(datasource);
 
 
  return DSservice;
}
 
@Override
public void closeConnection() {
  if(connection != null) {
   connection.closeConnection();
  }
}
}

JasperServerCustomDataSourceFactory.java

package com.jasperserver.custom.datasource;
 
 
import com.jaspersoft.jasperserver.api.metadata.common.service.RepositoryService;
import com.jaspersoft.jasperserver.api.metadata.jasperreports.domain.ReportDataSource;
import com.jaspersoft.jasperserver.api.metadata.jasperreports.service.ReportDataSourceService;
import com.jaspersoft.jasperserver.api.metadata.jasperreports.service.ReportDataSourceServiceFactory;
import com.jaspersoft.jasperserver.api.common.service.BeanForInterfaceImplementationFactory;
//import com.jaspersoft.jasperserver.api.engine.jasperreports.util.DataSourceServiceFactory;
 
 
import com.jasperserver.custom.datasource.JasperServerCustomDataSource;
 
 
public class JasperServerCustomDataSourceFactory implements ReportDataSourceServiceFactory {
private RepositoryService repositoryService;
private BeanForInterfaceImplementationFactory dataSourceServiceFactory;
 
public JasperServerCustomDataSourceFactory() {
}
 
/* Factory methods */
public JasperServerCustomDataSource createDataSourceService() {
  return new JasperServerCustomDataSource(repositoryService, dataSourceServiceFactory);
}
 
@Override
public ReportDataSourceService createService(ReportDataSource dataSource) {
  return new JasperServerCustomDataSource(repositoryService, dataSourceServiceFactory);
}
 
 
/* getters */
public RepositoryService getRepositoryService() {
  return repositoryService;
}
 
public BeanForInterfaceImplementationFactory getDataSourceServiceFactory() {
  return dataSourceServiceFactory;
}
 
/* Setters */
public void setRepositoryService(RepositoryService repositoryService) {
  this.repositoryService = repositoryService;
}
 
public void setDataSourceServiceFactory(BeanForInterfaceImplementationFactory dataSourceServiceFactory) {
  this.dataSourceServiceFactory = dataSourceServiceFactory;
}
}

ApplicationContext-customds.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
    <bean id="JasperServerCustomDataSourceFactory"
          class="com.jasperserver.custom.datasource.JasperServerCustomDataSourceFactory" >
       <property name="repositoryService">
            <ref bean="repositoryService"/>
        </property>
    </bean>
</beans>

oscar16071987's picture
Joined: Apr 28 2014 - 2:57pm
Last seen: 4 years 11 months ago

5 Answers:

0

Hi Oscar,

I follow your sample and the JR Server Ultimate Guide info about creating a custom datasource to make the same (switch datasource based on the user), and finally I got both working, but I prefer to use the custom datasource.

I think your code is basically OK (I uncommented the dataSourceServiceFactory, and use 

ExecutionContext context = JasperServerUtil.getExecutionContext();

instead of

ExecutionContext context = JasperServerUtil.getExecutionContext(LocaleContextHolder.getLocale());
If you prefer to use the custom data source sample on the guide, in the applicationContext_ds.XML, I have to include the bean references to repositoryService and dataSourceServiceFactories, to get them working, and to declare a propertyMap on the datasource service to hold the properties.
I paste the sources I use, hope this works for you.
Regards,
Álvaro.

MyCustomDataSourceService.Java

package com.example.jr.datasource;

import java.sql.Connection;

import java.sql.SQLException;

import java.util.Map;

import net.sf.jasperreports.engine.JRParameter;

import net.sf.jasperreports.engine.JRResultSetDataSource;

import org.springframework.security.context.SecurityContextHolder;

import com.jaspersoft.jasperserver.api.common.domain.ExecutionContext;

import com.jaspersoft.jasperserver.api.common.service.BeanForInterfaceImplementationFactory;

import com.jaspersoft.jasperserver.api.engine.jasperreports.service.impl.JdbcDataSourceService;

import com.jaspersoft.jasperserver.api.engine.jasperreports.service.impl.JdbcReportDataSourceServiceFactory;

import com.jaspersoft.jasperserver.api.metadata.common.service.RepositoryService;

import com.jaspersoft.jasperserver.api.metadata.jasperreports.domain.ReportDataSource;

import com.jaspersoft.jasperserver.api.metadata.jasperreports.service.ReportDataSourceService;

import com.jaspersoft.jasperserver.api.metadata.user.domain.impl.client.MetadataUserDetails;

import com.jaspersoft.jasperserver.war.common.JasperServerUtil;

public class MyCustomDataSourceService implements ReportDataSourceService {

// private properties

private JdbcDataSourceService connection;

private Connection conn;

// Bean properties

private Map propertyMap;

private RepositoryService repository;

private BeanForInterfaceImplementationFactory dataSourceServiceFactory;

/**

* Default constructor

*/

public MyCustomDataSourceService() {

super();

}

public Map getPropertyMap() {

return propertyMap;

}

public void setPropertyMap(Map propertyMap) {

this.propertyMap = propertyMap;

}

public RepositoryService getRepository() {

return repository;

}

public void setRepository(RepositoryService repository) {

this.repository = repository;

}

public BeanForInterfaceImplementationFactory getDataSourceServiceFactory() {

return dataSourceServiceFactory;

}

public void setDataSourceServiceFactory(

BeanForInterfaceImplementationFactory dataSourceServiceFactory) {

this.dataSourceServiceFactory = dataSourceServiceFactory;

}

@Override

public void closeConnection() {

if (conn != null) {

try {

conn.close();

} catch (SQLException e) {

}

}

if (connection != null) {

connection.closeConnection();

}

}

@Override

public void setReportParameterValues(Map parameterValues) {

MetadataUserDetails userDetails = (MetadataUserDetails) SecurityContextHolder

.getContext().getAuthentication().getPrincipal();

String userName = userDetails.getUsername();

String dataSourceURI = "/datasources/" + userName;

connection = getRepositoryDatasource(dataSourceURI);

try {

conn = connection.getDataSource().getConnection();

parameterValues.put(JRParameter.REPORT_CONNECTION, conn);

} catch (SQLException sqle) {

//

}

}

private JdbcDataSourceService getRepositoryDatasource(String repositoryURI) {

try {

ExecutionContext context = JasperServerUtil.getExecutionContext();

ReportDataSource datasource = (ReportDataSource) repository

.getResource(context, repositoryURI);

JdbcReportDataSourceServiceFactory factory = (JdbcReportDataSourceServiceFactory) dataSourceServiceFactory

.getBean(datasource.getClass());

JdbcDataSourceService DSservice = (JdbcDataSourceService) factory

.createService(datasource);

return DSservice;

} catch (Exception ex) {

return null;

}

}

}

applicationContext-MyCustomDS.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

<!-- define a custom data source -->

<bean id="CustomDataSource" class="com.jaspersoft.jasperserver.api.engine.jasperreports.util.CustomDataSourceDefinition">

<!-- this prop is always the same; it registers the custom ds -->

<property name="factory" ref="customDataSourceServiceFactory"/>

<!-- name used in message catalog and elsewhere -->

<property name="name" value="CustomDataSource"/>

<!-- class name of implementation -->

<property name="serviceClassName" value="com.example.jr.datasource.MyCustomDataSourceService"/>

<!-- definitions of properties you can edit -->

<property name="propertyDefinitions">

<list>

<map>

<entry key="name" value="repository"/>

<entry key="hidden" value="true"/>

<entry key="default" value-ref="repositoryService"/>

</map>

<map>

<entry key="name" value="dataSourceServiceFactory"/>

<entry key="hidden" value="true"/>

<entry key="default" value-ref="dataSourceServiceFactories"/>

</map>

</list>

</property>

</bean>

</beans>

amarco's picture
3
Joined: Jun 15 2014 - 11:52pm
Last seen: 4 years 11 months ago

Man!, Oh man, Sorry for late response and thanks for your help, I will check out and come back with feedback. Best regards!

oscar16071987 - 4 years 11 months ago

Few questions:
1. In the above steps ; customdatasourceservicefactory is not defined, but is mentioned in application context as Bean ID. Is this a separate class ? where is the reference.
2. Do we have complete steps with reference to achieve this.

chanduthedev - 4 years 11 months ago

In this case what bean name and bean method do we need to provide while creating bean data source?

naikrish94 - 1 year 11 months ago
show 1 more...

@naikrish94 found a solution?

bumaviru - 1 year 1 month ago
0

Hi Oscar

When we followed exact steps mentioned above, we are facing issues with Bean Data source. We have given Bean name as JasperServerCustomDataSourceFactory as specified in context.xml and it says no bean named is defined.  Could you please let us know, how the connection is successful in your above mentioned data source. 

Thanks.

 

chanduthedev's picture
Joined: Mar 24 2014 - 4:14am
Last seen: 3 years 6 months ago

Hi @chanduthedev, Sadly, Finally I used sub-reports and templates for each customer. But @amarco answer has the solution. Check out the answer and give us feedback. Best regards!

oscar16071987 - 4 years 11 months ago
0

Hi,

It passed a while, so I dont' fully remember the details, but there where two approaches to achieve this, the bean data source and the custom data source.

When I tried this, I got errors about beans not defined, or not accesing some properties, so I have to include the changes commented in my previous post, and the files "pasted" (I was not able to include in a friendly way...) work fine with the custom data source approach.

Another problem I had was when testing the custom datasource, was trying to appy changes in the java code and the contest.xml to a custom data source already defined. It seems that some metadata was stored elsewhere (I don't know anything about Spring) and changes has no "total" effect", so it was safer to delete the custom data source, update the code and start again defining a new fresh custom data source. That produces me serious headaches until I discover what was happening...

Regards,

Álvaro.

amarco's picture
3
Joined: Jun 15 2014 - 11:52pm
Last seen: 4 years 11 months ago
0

any solution for this issue?? any help would be appreciated. thanks.

naikrish94's picture
Joined: Oct 12 2017 - 9:49pm
Last seen: 1 year 11 months ago
0

I'm using version 4.5 and I have the same problem. Has anyone successfully deployed? could share?

bumaviru's picture
Joined: Sep 25 2018 - 7:22pm
Last seen: 1 year 1 month ago
Feedback