Chain of responsibility pattern - tight coupling with descendants - java

I came to problem how to put the actions into a chain with possibility to pass additional parameters during processing of a action.
Let's consider simple chain of a processes. Input is an object representing an image.
First image is resized, then deployed to ftp and saved to db.
Using a chain of responsibility pattern, calling could look like this:
ImageProcessor p = new ImageResizer(desiredSize);
p.setNext(new (new ImageDeployer(ftpServer, path)));
p.setNext(new (new ImageDbSaver(dbConnection, table)));
p.process(image);
p.close();
This is working perfectly for one image.
I would like to process images in a loop and set desiredSize and path there.
I cannot create and close connections every time, so code has to be spread:
ImageProcessor p = new ImageResizer();
p.setNext(new (new ImageDeployer(ftpServer)));
p.setNext(new (new ImageDbSaver(dbConnection, table)));
for(Image image : images) {
p.process(image, size, path);
}
p.close();
A problem of the solution is that the ImageProcessor shouldn't know about a size and a path. In case when is used only the ImageDbSaver parameters like size and path doesn't make sense.
What is a better way how to do it?

I guess the most robust solution in your case it so add some kind of processing context.
In simplest case, you can (1) use, for example Map<String, Object> for this, (2) pack it with arguments specific for various processors, (3) pass it into p.process(...) and (4) then extract, for example size in the processor that resizes the image.
This way you'll get flexibility to add new arguments without need to change signature of ImageProcessor and keeping implementers decoupled form one another.
The real world example of something similar would be request\session\servlet contexts in Java EE. You can put stuff into them on various lifecycle stages (for example security configuration options about what urls should require auth) and then fetch this stuff where needed (for example in Filter to block\allow access to resource based on auth requirements).
UPDATE
Updating the answer with code example to demonstrate the idea.
So, somewhere in your code you have place where you build your processor chain:
ImageProcessor p = new ImageResizer(desiredSize);
p.setNext(new (new ImageDeployer(ftpServer, path)));
p.setNext(new (new ImageDbSaver(dbConnection, table)));
In (possibly) other place you create and configure your processing context (it is not really required to configure all processors in one place):
Map<String, Object> context = new HashMap<String, Object>();
context.put("image_width", new Integer(640));
In another place in your code you do your processing, passing context to it (I reuse context for all processings but you might use different contexts for every image):
for(Image image : images) {
p.process(image, context);
}
p.close();
Now, somewhere in your ImageResizer:
#Override
void process(Image image, Map<String, Object> context) {
// ...
Integer imageWidth = (Integer) context.get("image_width");
// ...
}
So, context is a common place that helps to deliver data to specific processors, abstracting the details about this data and thus decoupling specific processors from one another.

You could simply store all processors into variables and then chain them.
ImageResizer resizer = new ImageResizer();
ImageDeployer deployer = new ImageDeployer(ftpServer);
ImageDbSaver saver = new ImageDbSaver(dbConnection, table);
resizer.setNext(deployer).setNext(saver);
for(Image image : images) {
deployer.setPath(somePath);
resizer.setDesiredSize(desiredSize);
resizer.process(image);
}
resizer.close();

A simple way of solving it would be to construct the invariants outside your loop. For example:
ImageDeployer deployer = new ImageDeployer(ftpServer);
ImageDbSaver dbSaver = new ImageDbSaver(dbConnection, );
for(Image image : images) {
ImageProcessor p = new ImageResizer(desiredSize);
p.setNext(deployer);
p.setNext(dbSaver);
p.process(image);
}
dbSaver.close();
deployer.close();
If ImageResizer needs to be closed you'll need some way of detaching things in the loop.

How would you code this if performance was not a problem? I think constructing a custom processor chain for every image would be a good solution then because you seem to have different values for every image.
Now if it turns out that this is too slow (which certainly can happen), why not pass a DatabaseConnection and FtpConnection object (which are initialized outside the loop) to the processors that need these?

Related

JMeter as code assertions are not being considered in test results

I'm using JMeter as a code (programmatic approach instead of GUI, with a Java Maven project) in order to stress-test an AWS Lambda Serverless API.
I've already developed a test plan, thread group, HTTPSamplerProxy and so on...
The execution of the calls to the API works perfect but is not the case e.g. for the DurationAssertion I've added to the HTTP Sampler..
I've also set a CSV file for the output where after execution I see everything ok (status code 200..), but the test should fail due to it is over the DurationAssertion I've configured (in addition to other assertion test elements).
I thought that perhaps I had to set "enabled" = true in the DurationAssertion object, but no effect.. Also, I've tried to access the JMeter Context in this way:
JMeterContextService.getContext().getPreviousResult()
I expected above code to retrieve a SampleResult (which has an AssertionResult collection), but the SampleResult is null..
A test plan with test elements (DurationAssertion in this case) without its respective analysis of the results of these assertions make no sense.. I want to see a failure message in each call that exceeds a certain threshold.. If I'd be using the JMeter GUI, I would add a ViewResultTree, which shows a Sampler Result view with detail of the request, response, and associated test asserts. And in addition to assertion result (per each request) I wanna see the request payload, full response, headers.. But in programmatic mode (without using the GUI).
So I would highly appreciate if anyone could give me some hint in how to accomplish this goal but by code.
UPDATE 1: I share a github snippet with the entire source code, such as UBIK LOAD PACK user suggested me:
https://gist.github.com/svillarreal/5eb90a66b8972633b95c249abb3566da
UPDATE 2: Inspection of context object (evaluated after JMeter engine finished run) - All null inside
UPDATE 3
i) I've recently found a jmeter.properties file, where I've configured the following properties:
jmeter.save.saveservice.output_format=xml
jmeter.save.saveservice.assertion_results=all
And now the output as XML instead of CSV shows, at least, the sent request payload and the response data, which is VERY useful for analyse error cases.
ii) I did the inspection of JMeterContextService.getContext() inside the JMeterEngine execution instead of after it finishes run and then I could realize that there is one context per thread group, and during its run this object is full so now is clear why in UPDATE 2 all the properties are null..
Best regards and thanks!
I can think about at least one use case when your approach will not work: JMeter didn't receive response from the server at all.
For example if your server gets overloaded it might be the case that JMeter will never get response back therefore your Duration Assertion will simply not be applied as PostProcessors, Listeners and Assertions are not fired given that SampleResult is null.
So in order to be on the safe side I would recommend applying connect and response timeouts to your HTTP Request sampler(s)
HTTPSamplerProxy httpSampler = new HTTPSamplerProxy();
httpSampler.setConnectTimeout("3000");
httpSampler.setResponseTimeout("3000");
//etc.
If you have > 1 HTTP Request sampler in Test Plan it makes sense to go for HTTP Request Defaults instead of setting the timeouts individually.
Finally I could fix this. The issue was that I was managing erroneously the tree that is passed to the StandardJMeterEngine.
In JMeter everything is based on this tree, and like in the GUI, we should take care about how the elements are positioned in its hierarchy.
Analysing the library and debugging it intensely I've realized more in deep how JMeter works and I've understood that everything is managed starting from the HashTree. So the solution was to add the DurationAssertion and ResponseAssertion as HTTPSamplerProxy node's childs instead of putting them as HTTPSamplerProxy's test elements.
In particular, the method that fills the assertions to check after the execution is the following (and that let me know how to manage the hashtree):
// org.apache.jmeter.threads.TestCompiler
private void saveSamplerConfigs(Sampler sam) {
List<ConfigTestElement> configs = new LinkedList<>();
List<Controller> controllers = new LinkedList<>();
List<SampleListener> listeners = new LinkedList<>();
List<Timer> timers = new LinkedList<>();
List<Assertion> assertions = new LinkedList<>();
LinkedList<PostProcessor> posts = new LinkedList<>();
LinkedList<PreProcessor> pres = new LinkedList<>();
for (int i = stack.size(); i > 0; i--) {
addDirectParentControllers(controllers, stack.get(i - 1));
List<PreProcessor> tempPre = new LinkedList<>();
List<PostProcessor> tempPost = new LinkedList<>();
List<Assertion> tempAssertions = new LinkedList<>();
for (Object item : testTree.list(stack.subList(0, i))) {
if (item instanceof ConfigTestElement) {
configs.add((ConfigTestElement) item);
}
if (item instanceof SampleListener) {
listeners.add((SampleListener) item);
}
if (item instanceof Timer) {
timers.add((Timer) item);
}
if (item instanceof Assertion) {
tempAssertions.add((Assertion) item);
}
if (item instanceof PostProcessor) {
tempPost.add((PostProcessor) item);
}
if (item instanceof PreProcessor) {
tempPre.add((PreProcessor) item);
}
}
assertions.addAll(0, tempAssertions);
pres.addAll(0, tempPre);
posts.addAll(0, tempPost);
}
SamplePackage pack = new SamplePackage(configs, listeners, timers, assertions,
posts, pres, controllers);
pack.setSampler(sam);
pack.setRunningVersion(true);
samplerConfigMap.put(sam, pack);
}
Also I had to activate the following property:
jmeter.save.saveservice.assertion_results_failure_message=true
As a consequence now I have my CSV file report with the assertions results messages included in a exclusive column for that.
Well, issue resolved. ** I've updated the github snippet gist with the final solution ** Many thanks to all that read this post and tried to collaborate.
Best regards,

IBM RTC API - Adding files to change sets

Basically I'm experimenting with the IBM Rational Team Concert Plain Java Client API, and I'm stuck at adding operations to change sets.
I create a new change set, retrieve the Operation factory and then I'd like to add a new file from the local machine file system (might be a new file of a project).
val changeSetHandle = workspaceConnection.createChangeSet(component, null)
val operationFactory = workspaceConnection.configurationOpFactory()
val saveOperation = operationFactory.save(...)
I do not understand how to to obtain an IVersionable handle to submit to the save() method.
You can refer to this thread which shows an example of IVersionable:
// Create a new file and give it some content
IFileItem file = (IFileItem) IFileItem.ITEM_TYPE.createItem();
file.setName("file.txt");
file.setParent(projectFolder);
// Create file content.
IFileContentManager contentManager = FileSystemCore.getContentManager(repository);
IFileContent fileContent = contentManager.storeContent(
"UTF-8",
FileLineDelimiter.LINE_DELIMITER_LF,
new VersionedContentManagerByteArrayInputStreamPovider(BYTE_ARRAY),
null,
null);
file.setContent(fileContent);
file.setContentType(IFileItem.CONTENT_TYPE_TEXT);
file.setFileTimestamp(new Date());
workspaceConnection.configurationOpFactory().save(file);
However, this is not enough:
IConfigurationOpFactory is used to update a repository workspace by adding changes to a change set.
The usage pattern is to get a workspace connection, create a bunch of save operations, then run IWorkspaceConnection#commit() on those ops.
Calling save() without committing the change drops the op onto the stack for the garbage collector to gobble up. ;)

Mounting a Vert.x sub-router on a path with path parameters

I want to create a URL structure for my Vert.x Web powered API that makes it clear how some entities are "contained" inside other entities and how you "traverse the entity path" to find child entities, so I'm thinking of using something like this to address a "grand child" (I don't expect anything deeper than a grand child):
GET /entity/:parent_id/sub-entity/:child_id/subsub-entity/:grandchild_id
So normally my Router configuration will look something like this:
router.get("/entity/:parent_id/sub-entity/:child_id/subsub-entity/:grandchild_id")
.handler(r -> {
HttpServerRequest req = r.request();
Minipart p = Entities.get(req.getParameter("parent_id"))
.getPart(req.getParameter("child_id"))
.getMinipart(req.getParameter("grandchild_id"));
// do something with p
});
When I add a lot of operations (each entity class at each level has catalog and create operations, and each level entity instance has get, update and delete operations, as well as a few other tidbits), my router class gets really large.
I was thinking of using sub-routers to offload the sub-entity management down the line, so the Entities Router configuration might do:
router.mountSubRouter("/entity/:parent_id/sub-entity", PartsRouter.init(vertx));
and then PartsRouter can do:
router.get("/:child_id").handler(r -> {
String parentEntityId = r.request().getParameter("parent_id");
Entity parent = Entities.get(parentEntityId);
String myid = r.request().getParameter("child_id");
Part myself = parent.getPart(myid);
// do something with myself
});
But when I do try that and try to access the sub-router operations, I get a 404 error from Vert.x...
Update:
Apparently Vert.x explicitly does not support this - it threw an exception that my wrapper code just logged and ignored, saying:
java.lang.IllegalArgumentException: Can't use patterns in subrouter mounts
So, is there another way to achieve what I'm trying to do (split a large router configuration into a proper class hierarchy)?
I can image 2 ways of solving your problem:
The first one would be to have a initial handler that processes the common part of the request and calls next so the following one will continue where the first stopped e.g.:
router.route("/entity/:parent_id/sub-entity", ctx -> {
// common part here...
ctx.next();
});
And then:
router.route("/entity/:parent_id/sub-entity/:child_id", ctx -> {
String parentEntityId = r.request().getParameter("parent_id");
Entity parent = Entities.get(parentEntityId);
String myid = r.request().getParameter("child_id");
Part myself = parent.getPart(myid);
// do something with myself
});
Alternatively you can use internal redirects, so you handle the initial code as before but instead of calling next() you redirect to another URL. In that case you should store in the context what you want to reuse since the request will be restarted in the new location.

Java how to read parameters from both file and cli?

I'm writing a tool in java and I need to provide some parameters that user can set.
I thought it is good to have ability to save all parameters in a file (and just run the .jar) and to alter saved parameters through command line.
So, I need to somehow handle parameters from two sources (priority, validity, etc.). Currently I use Apache.commons.cli to read cli-provided parameters and java.util.Properties for file-provided properties. And then I combine these properties together (and add some defaults if needed). But I don't like the result, it seems over-complicated to me.
So the code is something like this:
Properties fromFile = new Properties();
fromFile.load(new FileInputStream("settings.properties"));
cli.Options cliOptions = new cli.Options();
cliOptions.addOption(longName, shortName, hasArg, description);
//add more options
Parser parser = new DefaultParser();
CommandLine fromCli = parser.parse(cliOptions, args);
//at this point I have two different objects with properties I need,
//and I need to get every property from fromCli, check it's not empty,
// if it is, get it from fromFile, etc
So the question is: is there any library to handle properties from different sources (cli, file, defaults)? I tried googling, but did not succeed. Sorry if my googling skills are just not enough.
I'd like the code to be something like this:
import org.supertools.allPropsLib;
allPropsLib.PropsHandler handler = new allPropsLib.PropsHandler();
handler.addOptions(name, shortName, hasArg, description, defaultsTo);
handler.addSource(allPropsLib.Sources.CLI);
handler.addSource(allPropsLib.Sources.FILE);
handler.addSource(allPropsLib.Sources.DEFAULTS);
handler.setFileSource("filename");
allPropsLib.PropsContainer properties = handler.readAllProps();
// and at this point container should contain properties combined
// maybe there should be some handler function to tell the priorities,
// but I don't need to decide from where each properties should be taken
After you define the properties, load them into a java.util.Properties container regardless of the source. Then call the logic and pass it the container as a parameter.

How to get doc from couchdb without some fields? using Ektorp if possible

At first I misunderstood my problem and posted this question : Can someone explain me Cascading and FetchType lazy in Ektorp?
What I need to do: I need to save an Entity in couchdb and then have way to read it and potentially ignore some fields.
So I came up with this solution: I create a show function that delete fields from an object and then send it back.
function(doc, req) {
var result = doc;
var ignore = JSON.parse(decodeURIComponent(req.query.ignore)); //this is an array of field names
for (var i = 0, j = ignore.length; i < j; i++) {
if (result[ignore[i]]) {
delete result[ignore[i]];
}
}
return {
body : JSON.stringify(result),
headers : {
"Content-Type" : "application/json"
}
};
}
I have the same function but reversed in which the object keeps the fields I tell the function to keep.
Is there a better way to do this?
I also want to use Ektorp to call this but it allows me to only call Views. Right now I am forced to manage the http request myself. Is there a way to avoid this?
Right now this is the code I must use, but I would like to use Ektorp to do this.
HttpClient httpClient = new StdHttpClient.Builder().url("http://localhost:5984").build();
CouchDbInstance dbInstance = new StdCouchDbInstance(httpClient);
CouchDbConnector db = new StdCouchDbConnector("mydatabase", dbInstance);
db.createDatabaseIfNotExists();
String[] forget = new String[] { "field_to_ignore" };
String uri = "/mydatabase/_design/mydesigndoc/_show/ignorefields/mydocid?ignore=" + URLEncoder.encode(Json.stringify(Json.toJson(forget)), "UTF-8");
System.out.println(uri);
HttpResponse r = db.getConnection().get(uri);
String stuff = new Scanner(r.getContent()).useDelimiter("\\A").next();
System.out.println(stuff);
A show function isn't a terrible idea, from a CouchDB point of view. Ektorp may not support them, presumably because they're not hugely used, but Ektorp's open-source and on Github; you could easily just add this functionality, especially since you already have the basics of a working implementation of it.
Alternatively you could just build a view that does this for a given set of fields. You can't really parameterize this though, so you'd need well-defined sets of fields you know beforehand.
Finally I'd suggest either pulling the whole document and not worrying about it (unless you're in an extremely hugely bandwidth-limited situation it's probably not going to matter), or splitting the document into the constituent parts you're querying for and requesting them independently, if that's definitely the unusual case.

Categories

Resources