Generating password protected pdf. How to get unique password for every user? - jasper-reports

I've uploaded my reports on JasperServer where I'm scheduling the reports and send the pdf as attachments in emails to the users using the jobs rest api. Everything works perfectly, however we also need the pdf's to be encrypted. I've read the wiki topic and was able to encrypt the pdf.
But we want the passwords to be dynamic and be different for every user(for exmaple some combination of their phone numbers and date of births). The example described in the link specifies the password as a report property in the jrxml.
<property name="net.sf.jasperreports.export.pdf.user.password" value="123456"/>
<property name="net.sf.jasperreports.export.pdf.owner.password" value="123456"/>
The password is specified as a string and is similar for every pdf generated from this jrxml.
I tried something like this
<property name="net.sf.jasperreports.export.pdf.user.password" value="{$F{dateOfBirth}}"/>
where $F{dateOfBirth} is the dateOfBirth of the user for which the query is being run. But instead of putting in the field value, it just considers it a string and sets the password to="{$F{dateOfBirth}}"
How do I go along with this? Is their any way for me to set different passwords for every user?
NOTE:The datasource is configured for the report on the jasperserver. On the job execution api call, Jasperserver executed the query, fills the report, exports as pdf and sends it as email to the user.

Add the following code in your Java code.
JasperPrint print = JasperFillManager.fillReport(jasper, parameters, beanColDataSource2);
print.setProperty("net.sf.jasperreports.export.pdf.user.password", "jasper123");
Add in JRXML.
property name="net.sf.jasperreports.export.pdf.encrypted" value="True"
property name="net.sf.jasperreports.export.pdf.128.bit.key" value="True"
property name="net.sf.jasperreports.export.pdf.permissions.allowed" value="PRINTING"

As one comment mentioned, just use Java.
Here is an example, how I would code this (it's not perfect, but I think you will get it):
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import net.sf.jasperreports.engine.JRDefaultScriptlet;
import net.sf.jasperreports.engine.JRScriptletException;
import net.sf.jasperreports.engine.fill.JRFillParameter;
public class GetBirthdayScriptlet extends JRDefaultScriptlet {
private Connection conn;
private Connection getConnection() throws JRScriptletException {
if (conn == null) {
if (getParameterValue(JRFillParameter.REPORT_CONNECTION) != null) {
conn = (Connection) (getParameterValue(JRFillParameter.REPORT_CONNECTION));
} else {
throw new RuntimeException("No db-connection configured in the report!");
}
}
return conn;
}
public String getBirthday(String email) throws JRScriptletException, SQLException {
ResultSet result = null;
String resultString = null;
CallableStatement stmt = getConnection().prepareCall("select birthday from birthday_table where email = " + email);
stmt.executeUpdate();
result = stmt.getResultSet();
if(result.next()){
result.getString(1);
}
return resultString;
}
}
Pack this little snippet into a jar and add it to your Studio Build Path and also upload it to your Jaspersoft Server.
In your report outline rightlick on Scriptlets -> "Create Scriptlet"
The class of the scriptlet is GetBirthdayScriptlet (this is the codesnippet-class).
The expression you want to use in your report is:
$P{>>scriptlet-name<<_SCRIPTLET}.getBirthday("email#example.com")
Instead of entering the String, just use the parameter.
Also, maybe think of using the Jaspersoft Built In Parameter LoggedInUserEmailAddress
This helps if you want live-reports to be encrypted.

Related

Citrus framework: How to make a soap response / citrus variable / citrus function return result available to java

I'm using Citrus 2.7.8 with Cucumber 2.4.0. I'm making a soap call and want to get the response and do some advanced parsing on it to validate a graphql response has matching values. (I understand how to do validations when it's something that just has one element, but I need something able to handle when there could be one or many elements returned (for example, 1 vehicle or 4 vehicles)). To make my validation very dynamic and able to handle many different 'quotes', I want to store the response to a Citrus variable and then make it available to java to read in the file and do the advanced parsing and validation.
The TestContext injection doesn't appear to currently work with cucumber (see https://github.com/citrusframework/citrus/issues/657) so I'm using the workaround here:
How to inject TestContext using TestRunner and cucumber to manually create the context. Without this I get a nullpointerexception on anything with the context.
I am able to use Citrus's message function to grab the soap response which is awesome. My echo statements in the console show that it successfully put the right value into the citrus variable. But I'm having problems making that available to java so that I can then open it up and parse through it.
I've scaled down my step definition file to just the pertinent code. My couple attempts are listed below along with the problems I encountered in their results.
Does anyone have any ideas on how I can successfully workaround the context issues and make my response available to java?
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import com.consol.citrus.Citrus;
import com.consol.citrus.annotations.CitrusFramework;
import com.consol.citrus.annotations.CitrusResource;
import com.consol.citrus.config.CitrusSpringConfig;
import com.consol.citrus.context.TestContext;
import com.consol.citrus.dsl.junit.JUnit4CitrusTestRunner;
import com.consol.citrus.dsl.runner.TestRunner;
import com.consol.citrus.ws.client.WebServiceClient;
import cucumber.api.java.en.When;
#ContextConfiguration(classes = CitrusSpringConfig.class)
public class CitrusSteps extends JUnit4CitrusTestRunner {
#CitrusFramework
private Citrus citrus;
#CitrusResource
private TestRunner runner;
#CitrusResource
private TestContext context;
#Autowired
private WebServiceClient getQuote;
#When("^I call getQuote with id \"([^\"]*)\"$")
public void i_call_getquote_with_id(String quoteId) throws Throwable {
context = citrus.createTestContext();
String soappayload = "my payload (taken out for privacy purposes)";
runner.soap(action -> action.client(getQuote)
.send()
.soapAction("getQuote")
.payload(soappayload));
runner.soap(action -> action.client(getQuote)
.receive()
.name("getQuoteResponseStoredMessage"));
//this bombs out on the context line with this: "com.consol.citrus.exceptions.CitrusRuntimeException: Unknown variable 'messageStoreGetQuoteResponse1'"
runner.variable("messageStoreGetQuoteResponse1", "citrus:message(getQuoteResponseStoredMessage.payload())");
runner.echo("First try: ${messageStoreGetQuoteResponse1}");
String firstTry = context.getVariable("messageStoreGetQuoteResponse1");
log.info("First Try java variable: " + firstTry);
//this bombs out on the context line with this: "com.consol.citrus.exceptions.CitrusRuntimeException: Unknown variable 'messageStoreGetQuoteResponse2'"
runner.createVariable("messageStoreGetQuoteResponse2", "citrus:message(getQuoteResponseStoredMessage.payload())");
runner.echo("Second try: ${messageStoreGetQuoteResponse2}");
String secondTry = context.getVariable("messageStoreGetQuoteResponse2");
log.info("Second Try java variable: " + secondTry);
//This stores the literal as the value - it doesn't store the message so it appears I can't use citrus functions within the context
context.setVariable("messageStoreGetQuoteResponse3", "citrus:message(getQuoteResponseStoredMessage.payload())");
String thirdTry = context.getVariable("messageStoreGetQuoteResponse3");
log.info("Third Try java variable: " + thirdTry);
}
}
A smart co-worker figured out a workaround for the injection not working w/ cucumber.
I replaced these two lines:
#CitrusResource
private TestContext context;
with these lines instead:
TestContext testContext;
public TestContext getTestContext() {
if (testContext == null) {
runner.run(new AbstractTestAction() {
#Override
public void doExecute(TestContext context) {
testContext = context;
}
});
}
return testContext;
}
Then within my step where I want the context, I can use the above method. In my case I wanted my message response, so I was able to use this and confirm that the response is now in my java variable:
String responseXML = getTestContext().getMessageStore().getMessage("getQuoteResponseStoredMessage").getPayload(String.class);
log.info("Show response XML: " + responseXML);

Can we customize mapping file names in Wiremock?

I am recording the application through Wiremock using JAVA DSL, Do we have the option to customize the mapping file names? instead of getting the filename which is generated from wiremock..
Example: searchpanel_arrivalairport_th-72f9b8b7-076f-4102-b6a8-aa38710fde1b.json (Generated form wiremock using java )
I am expecting the above file name with my desired naming convention like
seacrpanel_airport_LGW.json
Custom filenames can be added by customizing StubMappingJsonRecorder.
I added CustomStubMappingJsonRecorder and override writeToMappingAndBodyFile method.
if(fileName!=null && !fileName.equals("")){
mappingFileName=fileName+"-mapping.json";
bodyFileName=fileName+"-body.json";
}else {
mappingFileName = UniqueFilenameGenerator.generate(request.getUrl(),
"mapping", filed);
bodyFileName = UniqueFilenameGenerator.generate(request.getUrl(), "body",
fileId, ContentTypes.determineFileExtension(request.getUrl(),
response.getHeaders().getContentTypeHeader(), body));
}
There's no easy way to do this at the moment. It is however possible. As #santhiya-ps says you need to write your own implementation of RequestListener, probably using StubMappingJsonRecorder as a template.
You can't extend it and override writeToMappingAndBodyFile as that method is private, but that is the method you probably want to change.
import com.github.tomakehurst.wiremock.common.*;
import com.github.tomakehurst.wiremock.core.*;
import com.github.tomakehurst.wiremock.http.*;
import java.util.List;
import static com.github.tomakehurst.wiremock.core.WireMockApp.*;
class NameTemplateStubMappingJsonRecorder implements RequestListener {
private final FileSource mappingsFileSource;
private final FileSource filesFileSource;
private final Admin admin;
private final List<CaseInsensitiveKey> headersToMatch;
private final IdGenerator idGenerator = new VeryShortIdGenerator();
public NameTemplateStubMappingJsonRecorder(Admin admin) {
this.mappingsFileSource = admin.getOptions().filesRoot().child(MAPPINGS_ROOT);
this.filesFileSource = admin.getOptions().filesRoot().child(FILES_ROOT);
this.admin = admin;
this.headersToMatch = admin.getOptions().matchingHeaders();
}
#Override
public void requestReceived(Request request, Response response) {
// TODO copy StubMappingJsonRecorder changing as required...
}
}
You can then register your RequestListener as so:
WireMockServer wireMockServer = new WireMockServer();
wireMockServer.addMockServiceRequestListener(
new NameTemplateStubMappingJsonRecorder(wireMockServer)
);
wireMockServer.start();
So long as you still store the mapping files in the expected directory (stored in FileSource mappingsFileSource above, which will be ${rootDir}/mappings, where rootDir is configured as explained in Configuration - File Locations) they should be loaded successfully as all files with extension json in that dir are loaded as mappings.
It would be much easier if StubMappingJsonRecorder took a strategy for generating these names - it might be worth creating an issue on the WireMock repo asking for an easier way to do this. I'd suggest getting an agreement on a basic design before raising a PR though.

citrus waitFor().condition() statement not waiting when used with ftpServer

I'm trying to use the citrus-framework to test an integration that writes some files on a FTP server.
I need to wait until some file is uploaded to the ftp (I'm using waitFor().condition() statement to accomplish that) and then receive the messages sent and do some assertions.
import com.consol.citrus.annotations.CitrusTest;
import com.consol.citrus.condition.Condition;
import com.consol.citrus.context.TestContext;
import com.consol.citrus.dsl.testng.TestNGCitrusTestDesigner;
import com.consol.citrus.ftp.server.FtpServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ActiveProfiles;
import org.testng.annotations.Test;
import java.io.File;
#ActiveProfiles(value = "ftpTest")
#Test
public class FtpTest extends TestNGCitrusTestDesigner {
#Autowired
FtpServer ftpServer;
#Autowired
TestContext context;
#CitrusTest(name = "ftpTest")
public void ftpTest() {
// here I start my integration that uses a cron to upload the file
// this code is irrelevant for the example
Condition waitUntilFileIsUploaded = new Condition() {
#Override
public String getName () {
return "Check files on FTP";
}
#Override
public boolean isSatisfied (TestContext testContext){
return new File("/tmp/foo_dir").listFiles().length != 0;
}
#Override
public String getSuccessMessage (TestContext testContext){
return "Files found in FTP!";
}
#Override
public String getErrorMessage (TestContext testContext){
return "No file was found in FTP";
}
};
waitFor().condition(waitUntilFileIsUploaded).seconds(120L).interval(500L);
ftpServer.createConsumer().receive(context);
}
}
When I try to run this test looks like the waitFor() is never executed and ftpServer.createConsumer().receive(context); is executed before any file could be uploaded to the FTP.
This is the error that I'm getting:
ftpTest>TestNGCitrusTest.run:57->TestNGCitrusTest.run:111->TestNGCitrusTestDesigner.invokeTestMethod:73->TestNGCitrusTest.invokeTestMethod:133->ftpTest:49 ยป ActionTimeout
Any idea how I could fix this?
Also any complete example for using FTP Java DSL with Citrus would be more than welcome!
Please use test designer receive method instead of creating the consumer on your own.
receive(ftpServer)
.header("some-header", "some-value")
.payload("some payload");
Only then test designer can arrange the test actions in proper order. This is because test designer constructs the complete test action logic first and execution takes place at the very end of the test method.
As an alternative to that you could also use test runner instead of test designer. The runner will execute each test action immediately giving you the opportunity to add custom statements as you did before.

CQ5 - displaying a CQ.Notification in the frontend, when a workflow finished

I implemented workflows, but it would be nice to know if there are hooks provided by the client library which allow to hook in. When a workflow was triggered and finished, a CQ.Notification should be displayed. Or do i need to implement a polling library by myself?
As far as I know, there is no built-in CQ area to see when something is done, aside from looking here:
http://yoursite.com:port/libs/cq/workflow/content/console.html
Once there, you can go to the 'Instances' tab and see what's happening.
In one application that I worked on, we ended up writing our own method that sends notifications to us based on one of our workflows (our workflow ties into it - from the workflow models area, you can set your process to be a servlet that you've put into CQ). Here is the main piece of code from our servlet that catches the process being active, and then calls our methods to email us based on what it finds:
import com.day.cq.workflow.WorkflowException;
import com.day.cq.workflow.WorkflowSession;
import com.day.cq.workflow.exec.WorkItem;
import com.day.cq.workflow.exec.WorkflowData;
import com.day.cq.workflow.exec.WorkflowProcess;
import com.day.cq.workflow.metadata.MetaDataMap;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.osgi.framework.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import java.util.Arrays;
public class YourServletName implements WorkflowProcess {
#Override
public void execute(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap args) throws WorkflowException {
session = workflowSession.getSession();
final WorkflowData data = workItem.getWorkflowData();
String type = data.getPayloadType();
String[] argStrings = args.get("PROCESS_ARGS", ARG_UPDATED).split(",");
String reason = argStrings[0];
String baseUrl = argStrings[1];
try {
if (type.equals(TYPE_JCR_PATH) && data.getPayload() != null) {
String resourcePath = data.getPayload().toString();
logger.info("Send Notification that {} has been {}.", resourcePath, reason.toLowerCase());
if (resourcePath != null && !resourcePath.isEmpty()) {
ResourceInfo resourceInfo = new ResourceInfo(resourcePath, baseUrl);
sendEmail(resourceInfo, reason);
}
}
} catch (EmailException ex) {
logger.warn("Failed to send Email");
throw new WorkflowException(ex);
} catch (MailingException ex) {
logger.warn("Failed to send Email");
throw new WorkflowException(ex);
}
}
}
You can find more info in the documentation for Extending Workflow Functionality.
Look at the first code block on that page, and that will give you the best idea of how you can implement a custom workflow handler.
EDIT
If you want to see it on the front-end, you could do an AJAX call to get the JSON list of currently running workflows - you can hit this url:
http://localhost:4502/etc/workflow/instances.RUNNING.json
Then you could loop through them and see if yours is in there. This isn't very nice though, since they are all just listed by IDs. I would instead suggest using the querybuilder, or again, just doing an AJAX GET. This is one example:
1_group.0_path=/etc/workflow/instances
2_group.0_type=cq:Workflow
0_group.property.2_value=COMPLETED
0_group.property=status
0_group.property.and=true
3_group.property=modelId
3_group.property.2_value=/etc/workflow/models/your-model-name/jcr:content/model
3_group.property.and=true
Then the URL would look something like this:
http://yoursiteurl:port/libs/cq/search/content/querydebug.html?_charset_=UTF-8&query=http%3A%2F%2Fyoursiteurl%3Aport%3F%0D%0A1_group.0_path%3D%2Fetc%2Fworkflow%2Finstances%0D%0A2_group.0_type%3Dcq%3AWorkflow%0D%0A0_group.property.2_value%3DRUNNING%0D%0A0_group.property%3Dstatus%0D%0A0_group.property.and%3Dtrue%0D%0A3_group.property%3DmodelId%0D%0A3_group.property.2_value%3D%2Fetc%2Fworkflow%2Fmodels%2Fyour-model-name%2Fjcr%3Acontent%2Fmodel%0D%0A3_group.property.and%3Dtrue
It's ugly, but it gets you the results you need, and then you can parse them to get further information you need.

How to retrieve dynamic content from database?

I'm evaluating java-based cms and selecting one as our cms ,now I'm learning dotcms , I need to know how to retrieve content from db like traditional jsp/bo does,I'm new to dotcms, the official documents only tell how to add static content but dynamic content , say running a sql and getting the wanted data ,then putting them into pages. We are doing an internal website where employees can browse news, events, colleagues information etc which managed through a cms, the information is definitely dynamic and updated regularly. We plan to use spring mvc on the project. Any ideas on the question?
thank you.
To get this to work you need to do a few things:
If you want to use a different database, then you can add a new resource to the conf/Catalina/localhost/ROOT.xml file. If you want to use the dotCMS database to host the additional tables then you can skip this step.
From within your java code you can get a database connection using the DbConnectionFactory class. Now you can read the data from the database. Here's an example:
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
Connection conn = DbConnectionFactory.getConnection();
Statement selectStatement;
try {
selectStatement = conn.createStatement();
try {
selectStatement.execute("SELECT * FROM your_table WHERE your_where_clause etc...");
ResultSet result = selectStatement.getResultSet();
if (result.next()) {
.. do your stuff here...
// for example:
// Long dbId = result.getLong("Id");
// String stringField = result.getString("stringFieldName");
// int intField = result.getInt("intFieldName");
} finally {
selectStatement.close();
}
} catch (SQLException e1) {
// Log the error here
}
}
If you want to use this data in velocity you'll need to create a viewtool. Read more about that here: http://dotcms.com/docs/latest/DynamicPluginsViewtool