Vaadin 8 - Download Button for a text file with String content - scala

I want to assign String content to a variable and enable the user to download that String as a text file.
I know there is FileDownloader from Vaadin 8 which I can use but I don't want static file/image download capability but rather dynamic String content which can downloaded a text file in the browser.

The resource interface in Vaadin, that is used by FileDownloader is a bit cumbersome. Especially so for dynamically created content, whose generation you'll want to postpone until user actually clicks the download button, which is very common in typical Vaadin apps.
Viritin add-on
Thus, I suggest to add Viritin add-on to your application. Use the DownloadButton component from it, which simplifies the usage a lot.
Here is a trivial example:
DownloadButton simple = new DownloadButton(out -> {
try {
out.write("Foobar".getBytes());
} catch (IOException ex) {
// exception handling
}
}).withCaption("Simple Download");
To see more complete example, refer to the tests in the Viritin project. From the project you can also see the "raw solution" if you peruse the source code of DownloadButton class.
PS. I'm the author of Viritin, so kind of biased to suggest its usage, but I have also been working with Vaadin for Vaadin Ltd for over a decade.

Here's a simple solution in Scala. We create a ReportDownloader component which extends VerticalLayout. It contains a "Download" button which trigger text file download in the browser.
import com.vaadin.ui.{Button, VerticalLayout}
import com.vaadin.server._
import java.io.{ByteArrayInputStream}
class VaadinStringStream(str : String, browserFileNameSuggestion : String) extends ConnectorResource {
override def getMIMEType: String = "text/plain"
override def getFilename: String = browserFileNameSuggestion
override def getStream: DownloadStream = new DownloadStream(
new ByteArrayInputStream(str.getBytes), getMIMEType, getFilename
)
}
class ReportDownloader extends VerticalLayout{
val btn = new Button("DOWNLOAD")
this addComponent btn
val stream = new VaadinStringStream("This is a sample txt file content", "report.txt")
new FileDownloader(stream).extend(btn)
}
VaadinStringStream takes dynamic String content and a suggested filename for the browser as arguments.

Related

How to add a custom/dynamic target to a hyperlink

I am using jasperreports-6.14.0. As far as I can tell, there is only one way to add a custom hyperlink target to anything that allows hyperlinks. Please tell me there is a better way (other than putting javascript into my reference expression).
Implement the net.sf.jasperreports.engine.export.JRHyperlinkTargetProducer interface, looking in the hyperlink parameters for a specific, named parameter to return as your target string.
Extend net.sf.jasperreports.engine.export.HtmlExporter and set its targetProducerFactory protected field as an instance of your new custom hyperlink target producer.
It looks like this is the only option, but it just feels like there should be a way to skip step 2 by just setting the targetProducerFactory. It's almost like the Jasper devs started to do exactly that and thought "Nah, I just don't feel right about that. Let's take it out."
I am going to do the above unless some kind soul can show me a better way.
Custom target producers are loaded as extensions by the HTML exporter. You can register extensions either programmatically by creating the HTML exporter using your own JasperReportsContext instance, or package the extension in a jar and have it autodetected by the exporter.
If you control the HTML exporter creation you can pass the extension programmatically:
JRHyperlinkTargetProducer targetProducer = new JRHyperlinkTargetProducer() {
#Override
public String getHyperlinkTarget(JRPrintHyperlink hyperlink) {
return "foo";
}
};
JRHyperlinkTargetProducerMapFactory targetProducerFactory = new JRHyperlinkTargetProducerMapFactory();
targetProducerFactory.addProducer("mycustomtarget", targetProducer);
SimpleJasperReportsContext jasperReportsContext = new SimpleJasperReportsContext();
jasperReportsContext.setExtensions(JRHyperlinkTargetProducerFactory.class,
Collections.singletonList(targetProducerFactory));
HtmlExporter htmlExporter = new HtmlExporter(jasperReportsContext);
If you want to have the extension autodected you need to create a jar that contains a class like this:
public class CustomTargetProducerExtension implements ExtensionsRegistryFactory {
#Override
public ExtensionsRegistry createRegistry(String registryId, JRPropertiesMap properties) {
JRHyperlinkTargetProducer targetProducer = new JRHyperlinkTargetProducer() {
#Override
public String getHyperlinkTarget(JRPrintHyperlink hyperlink) {
return "bar";
}
};
JRHyperlinkTargetProducerMapFactory targetProducerFactory = new JRHyperlinkTargetProducerMapFactory();
targetProducerFactory.addProducer("mycustomtarget", targetProducer);
return new SingletonExtensionRegistry<>(JRHyperlinkTargetProducerFactory.class, targetProducerFactory);
}
}
And put a jasperreports_extension.properties resource in the root of the jar containing the line:
net.sf.jasperreports.extension.registry.factory.my.custom.target.producer=<package>.CustomTargetProducerExtension
Then your custom target producer would be automatically detected for elements that have hyperlinkTarget="mycustomtarget"

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.

Specs2/Guice issue in Play 2.4.0 functional tests

I'm having an issue with dependencies apparently bleeding between tests, which is causing most of the tests to fail. In each case, debugging shows the first app created in a test class is used for all tests, and this is resulting in the failures.
I've tried adding isolated and sequential and this has had no effect.
Am I doing something remarkably stupid or subtly stupid?
For example, here's SubjectNotPresentTest.scala
class SubjectNotPresentTest extends AbstractViewTest {
"show constrained content when subject is not present" in new WithApplication(testApp(handler())) {
val html = subjectNotPresentContent(FakeRequest())
private val content: String = Helpers.contentAsString(html)
content must contain("This is before the constraint.")
content must contain("This is protected by the constraint.")
content must contain("This is after the constraint.")
}
"hide constrained content when subject is present" in new WithApplication(testApp(handler(subject = Some(user())))) {
val user = new User("foo", Scala.asJava(List.empty), Scala.asJava(List.empty))
val html = subjectNotPresentContent(FakeRequest())
private val content: String = Helpers.contentAsString(html)
content must contain("This is before the constraint.")
content must not contain("This is protected by the constraint.")
content must contain("This is after the constraint.")
}
}
GuiceApplicationBuilder is used in a parent class is used to create the app for testing.
val app = new GuiceApplicationBuilder()
.bindings(new DeadboltModule())
.bindings(bind[HandlerCache].toInstance(LightweightHandlerCache(handler)))
.overrides(bind[CacheApi].to[FakeCache])
.in(Mode.Test)
.build()
You can see an example of the failures at https://travis-ci.org/schaloner/deadbolt-2-scala/builds/66369307#L805
All tests can be found at https://github.com/schaloner/deadbolt-2-scala/tree/master/code/test/be/objectify/deadbolt/scala/views
Thanks,
Steve
It looks like the problem is caused when the current Play application is statically referenced in a test environment in which there are multiple applications - even if they are logically separate.
Because components can't be injected (to the best of my knowledge) into templates, I created a helper object which uses Play.current.injector to define a couple of vals.
val viewSupport: ViewSupport = Play.current.injector.instanceOf[ViewSupport]
val handlers: HandlerCache = Play.current.injector.instanceOf[HandlerCache]
(It's also not possible, TTBOMK, to inject into objects, otherwise I could just inject the components into the object and everyone could go home).
A better approach is to expose what is required as an implicit.
object ViewAccessPoint {
private[deadbolt] val viewStuff = Application.instanceCache[ViewSupport]
private[deadbolt] val handlerStuff = Application.instanceCache[HandlerCache]
object Implicits {
implicit def viewSupport(implicit application: Application): ViewSupport = viewStuff(application)
implicit def handlerCache(implicit application: Application): HandlerCache = handlerStuff(application)
}
}
In the view, import the implicits and you're good to go.
#import be.objectify.deadbolt.scala.DeadboltHandler
#import be.objectify.deadbolt.scala.ViewAccessPoint.Implicits._
#import play.api.Play.current
#(handler: DeadboltHandler = handlerCache(current).apply(), name: String, meta: String = null, timeout: Function0[Long] = viewSupport.defaultTimeout)(body: => play.twirl.api.Html)(implicit request: Request[Any])
#if(viewSupport.dynamic(name, meta, handler, timeout(), request)) {
#body
}

How to programmatically new a java class which implements sepecified interface in eclipse plugin development

Friends,
Now we are developing a eclipse plugin, it contains a action to generated a service interface and it's impl stub.
Now the interface is generated, I want to use eclipse JDT to create a java class which implements sepecified interface, but don't know how.
The info we have:
the interface name, the impl class name, the packagename, the java project contains them.
Thanks in advance for your kindly help.
A quick scan of how the new class wizard does it, it seems that there is no public easy to use API for this. You can have a look at org.eclipse.jdt.ui.wizards.NewTypeWizardPage.createType(IProgressMonitor) method to see how JDT itself creates new classes.
It should be possible to extend the org.eclipse.jdt.ui.wizards.NewTypeWizardPage, so you can leverage the createType() method.
Probably the minimal steps you would have to do is simply generate source content into the correctly placed IFile. ex:
public Object execute(ExecutionEvent event) throws ExecutionException {
final String PACKAGE_PATH = "z.ex/src/z/ex/go";
final String CONTENT = "package z.ex.go;\n"
+ "public class RunAway {\npublic static void main(String[] args) {\n"
+ "System.out.println(\"Run Away\");\n}\n}\n";
final IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
final IResource packageResource = root.findMember(PACKAGE_PATH);
if (packageResource instanceof IFolder) {
IFolder packageFolder = (IFolder) packageResource;
final IFile file = packageFolder.getFile("RunAway.java");
try {
if (!file.exists()) {
file.create(new ByteArrayInputStream(CONTENT.getBytes()),
true, new NullProgressMonitor());
} else {
file.setContents(
new ByteArrayInputStream(CONTENT.getBytes()),
IFile.FORCE | IFile.KEEP_HISTORY,
new NullProgressMonitor());
}
} catch (CoreException e) {
e.printStackTrace();
}
}
return null;
}
See AbstractNewClassWizard for a smaller example that is similar to NewTypeWizardPage and uses some of the JDT APIs.
You can use the new class wizard to create classes.
This will prompt the user for the class name, et cetera. You can initialize the values of the wizard page. Below I am setting the source folder only (and tell the wizard that it cannot be changed, thus the second false parameter). You might want to set the interface and possible the package as well.
OpenNewClassWizardAction wizard = new OpenNewClassWizardAction();
wizard.setOpenEditorOnFinish(false);
NewClassWizardPage page = new NewClassWizardPage();
page.setPackageFragmentRoot(sourceFolder, false);
wizard.setConfiguredWizardPage(page);
wizard.run();
return (IType) wizard.getCreatedElement();
Hope that helps!
Create the entire java file using the JDT - AST. First create the AST and then write it to a java file. It might look as hefty work, but its the best one. You will have complete control.

Turn links in wicket panels to hyperlinks

I'm trying to find a way to automatically convert links in a panel to hyper-links. So for example a user input is:
"And here you can find my awesome example: http://example.com"
Is it possible in wicket to add an anchor element to each "http://..." text, so the above example would output
"And here you can find my awesome example: http://example.com"
instead?
You can use Wicket's built in SmartLinkLabel.
From the Javadoc:
If you have email addresses or web URLs in the data that you are displaying, then you can automatically display those pieces of data as hyperlinks, you will not have to take any action to convert that data.
One way to do this is to extend Label and override onComponentTagBody
Something like:
public class AnchorizeLabel extends Label {
public AnchorizeLabel(String id, String body) {
super(id, body);
}
#Override
protected void onComponentTagBody(MarkupStream stream, ComponentTag tag) {
String newBody = createAnchors(getDefaultModelObjectAsString());
replaceComponentTagBody(stream, tag, newBody);
}
private String createAnchors(String body) {
// regex magic to create links
}
}
You can also accomplish this with a custom IModel or IConverter but I prefer the Label approach.