GWT cross-domain rpc - gwt-rpc

I need to call a GWT application service from javascript which is running on different domain.
How could this be done? How do I point from my applicaton to the javascript url?
Thank you.

The idea behind a cross domain request is the your java script creats a script tag which loads a generated java script from the forgein url. When loaded the generated java script is evaluated and calls a callback function you created.
The following code ist not testet and shows the idea:
public class CrossSiteDomainRequest {
/** Counter to create unique ids for callback function. */
private static int idCounter = 0;
/** Url to load the javascript from. */
private String url;
/**
* Creates a new loader with the given <code>url</code>.
* #param url to load the java script from {#link #url}.
*/
public CrossSiteDomainRequest(String url) {
this.url = url;
}
/**
* Uses the {#link #url} to load the data from another url.
*/
public void load() {
String callbackId = "callbackId" + idCounter++;
String prepend = url.indexOf("?") != -1 ? "&" : "?";
String u = url + prepend + "callback=" + callbackId// Add more Parameters
createCallback(this, transId);
Element script = DOM.createElement("script");
script.setAttribute("src", u);
script.setAttribute("id", callbackId);
script.setAttribute("type", "text/javascript");
script.setAttribute("language", "JavaScript");
getHead().appendChild(script);
}
/**
* Destroys the callback with the given <code>id</code>.
* #param id of the script tag and native javascript callback function which should be destroyed.
*/
protected void destroyCallbackmethod(String id) {
getHead().removeChild(DOM.getElementById(id));
removeCallback(id);
}
/**
* This method is invoked by the callback to handel the loaded data.
* #param callbackId DOM-Id of the callback whick invoked this method.
* #param jso Object that encapsultes the loaded data.
*/
#SuppressWarnings("unchecked")
protected void onReceivedData(String callbackId, JavaScriptObject jso) {
try {
// Read data
} catch (Exception e) {
// Handle Error
}
destroyCallbackmethod(callbackId);
}
/**
* Creates a native javascript callback.
* #param cscr to invoke the {#link #onReceivedData(String, com.google.gwt.core.client.JavaScriptObject)} on when the data has been loaded.
* #param callbackId DOM-Id to create the callback back.
*/
private native void createCallback(CrossSiteDomainRequest cscr, String callbackId) /*-{
$wnd[callbackId] = function(j) {
proxy.#com.test.package.client.CrossSiteDomainRequest::onReceivedData(Ljava/lang/String;Lcom/google/gwt/core/client/JavaScriptObject;)(callbackId, j);
};
}-*/;
private native void removeCallback(String callbackId) /*-{
$wnd[callbackId] = null;
}-*/;
public static native Element getHead() /*-{
return $doc.getElementsByTagName('head')[0];
}-*/;
}
If you create a CrossSiteDomainRequest Object for the URL http://www.test.com/loadXDR.js
you have to evaluate the callbackId parameter and generate a java script which may looks like this:
callbackId({"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{"value": "New", "onclick": "CreateNewDoc()"},
{"value": "Open", "onclick": "OpenDoc()"},
{"value": "Close", "onclick": "CloseDoc()"}
]
}
}});
The callbackId has to be replaced accordingly.

Related

How to retrieve an InputStream from SmbRemoteFileTemplate?

I'm using spring integration for SMB to store and retrieve files from windows server.
In cases when I want to retrieve the file from the server I found the method "get" which receives a lamda function to handler the InputStream, but I need return this element and I wouldn't like to store in local and then return the InputStream.
Is there any alternative for this matter?
Thank you all.
My code is like this:
#Override
protected InputStream readMetadataFile(final String filename) throws FileNotFoundException {
final File inputFile = new File(filename);
if (this.smbRemoteFileTemplate.exists(filename)) {
this.smbRemoteFileTemplate.get(filename, in -> FileUtils.copyInputStreamToFile(in, inputFile));
return new FileInputStream(inputFile);
}
return null;
}
PS: does any mate with reputation greater than 1500 could create the tag "spring-integration-smb"? Thanks again.
The RemoteFileTemplate is based on the SessionFactory and there is an API like this:
/**
* Obtain a raw Session object. User must close the session when it is no longer
* needed.
* #return a session.
* #since 4.3
*/
Session<F> getSession();
That Session has this one for you:
/**
* Retrieve a remote file as a raw {#link InputStream}.
* #param source The path of the remote file.
* #return The raw inputStream.
* #throws IOException Any IOException.
* #since 3.0
*/
InputStream readRaw(String source) throws IOException;
Let's hope that this path is enough for your use-case!
Note: that you are responsible for closing this InputStream after using.

StreamingMessageSource keeps firing when a filter is applied

I am trying to poll an FTP directory for a certain kind of file, the polling of a directory works, but whenever I try to apply a filter to filter the files by extension, the messagesource keeps spamming messages about the file with no regard to the polling delay. Without the filters everything works fine, once I enable them my application authenticates with the FTP, downloads the file and sends the message nonstop over and over again. I have the following beans:
/**
* Factory that creates the remote connection
*
* #return DefaultSftpSessionFactory
*/
#Bean
public DefaultSftpSessionFactory sftpSessionFactory(#Value("${ftp.host}") String ftpHost,
#Value("${ftp.port}") int ftpPort,
#Value("${ftp.user}") String ftpUser,
#Value("${ftp.pass}") String ftpPass) {
DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory();
factory.setAllowUnknownKeys(true);
factory.setHost(ftpHost);
factory.setPort(ftpPort);
factory.setUser(ftpUser);
factory.setPassword(ftpPass);
return factory;
}
/**
* Template to handle remote files
*
* #param sessionFactory SessionFactory bean
* #return SftpRemoteFileTemplate
*/
#Bean
public SftpRemoteFileTemplate fileTemplate(DefaultSftpSessionFactory sessionFactory) {
SftpRemoteFileTemplate template = new SftpRemoteFileTemplate(sessionFactory);
template.setAutoCreateDirectory(true);
template.setUseTemporaryFileName(false);
return template;
}
/**
* To listen to multiple directories, declare multiples of this bean with the same inbound channel
*
* #param fileTemplate FileTemplate bean
* #return MessageSource
*/
#Bean
#InboundChannelAdapter(channel = "deeplinkAutomated", poller = #Poller(fixedDelay = "6000", maxMessagesPerPoll = "-1"))
public MessageSource inboundChannelAdapter(SftpRemoteFileTemplate fileTemplate) {
SftpStreamingMessageSource source = new SftpStreamingMessageSource(fileTemplate);
source.setRemoteDirectory("/upload");
source.setFilter(new CompositeFileListFilter<>(
Arrays.asList(new AcceptOnceFileListFilter<>(), new SftpSimplePatternFileListFilter("*.trg"))
));
return source;
}
/**
* Listener that activates on new messages on the specified input channel
*
* #return MessageHandler
*/
#Bean
#ServiceActivator(inputChannel = "deeplinkAutomated")
public MessageHandler handler(JobLauncher jobLauncher, Job deeplinkBatch) {
return message -> {
Gson gson = new Gson();
SFTPFileInfo info = gson.fromJson((String) message.getHeaders().get("file_remoteFileInfo"), SFTPFileInfo.class);
System.out.println("File to download: " + info.getFilename().replace(".trg", ".xml"));
};
}
I think AcceptOnceFileListFilter is not suitable for SFTP files. The returned LsEntry doesn't match previously stored in the HashSet: just their hashes are different!
Consider to use a SftpPersistentAcceptOnceFileListFilter instead.
Also it would be better to configure a DefaultSftpSessionFactory for the isSharedSession:
/**
* #param isSharedSession true if the session is to be shared.
*/
public DefaultSftpSessionFactory(boolean isSharedSession) {
To avoid session recreation on each polling task.
you don't have a 6 seconds delay between calls because you have a maxMessagesPerPoll = "-1". That means poll remote files until they are there in remote dir. In your case with the AcceptOnceFileListFilter you always end up with the same file by the hash reason.

How to render twig templates into a service. Is it Best practice?

I have the following Symfony 3 controller:
public function register(Request $request)
{
$username=$request->get('username');
$password=$request->get('password');
$email=$request->get('email');
$captchaResponse=$request->get('g-recaptcha-response');
$session =$request->getSession();
$res1 = new Response();
$response_data=array('status'=>0);
if($session->get('captcha')===$captchaResponse)
{
$en = $this->container->get('user_model');
$data=$en->register($username,$password,$email);
$res1->headers->set('Content-Type','text/json');
if($data['status']===false)
{
$response_data['data']="An Internal error Happened";
error_log($data['data']);
}
else if($data['status']===-1)
{
$response_data['data']=$data['data'];
}
else
{
$response_data['status']=1;
$response_data['data']="Please check your mail to confirm your registration.";
/*Send Email*/
$message = \Swift_Message::newInstance()
->setSubject('Please confirm your registration')
->setFrom('symphotest#openmailbox.org')
->setTo($email)
->setBody($this->renderView('emails/confirm.html.twig',array('token'=>$data['data'])))
->addPart(
$this->renderView('emails/registration.txt.twig',array('token'=>$data['data'])),
'text/plain'
);
$this->get('mailer')->send($message);
}
}
else
{
$response_data['data']="You have not given a correct captcha";
}
$res1->setContent(json_encode($response_data));
$session->set('captcha',uniqid());//Generate gibberish in order not to reuse the very same captcha again
return $res1;
}
And I have made the following service:
namespace AppBundle\Models;
use Doctrine\ORM\EntityManager;
use AppBundle\Util\ModelStatus;
use AppBundle\Exceptions\InvalidArgumentException;
use \SwiftMessage;
class UserModel
{
/** #var EntityManager */
private $em;
/** #var \Swift_Mailer */
private $mailer;
/** #var \Twig_Environment */
private $twig;
/**
*
* #param EntityManager $em
* #param \Swift_Mailer $mailer
* #param \Twig_Environment $twig
*/
public function construct(EntityManager $em, \Swift_Mailer $mailer,\Twig_Environment $twig)
{
$this->em=$em;
$this->$mailer=$mailer;
}
/**
* Performs the actions needed for Registration
*
* #param unknown $username
* #param unknown $password
* #param unknown $email
* #param \Swift_Message $registrationMessage
*
* #return ModelStatus
*/
public function register($username,$password,$email)
{
$modelStatus=new ModelStatus();
try
{
/** #var \AppBundle\Entity\UserRepository */
$repository=$this->em->getRepository('AppBundle::Users');
$token=$repository->register($username,$password,$email);
$modelStatus->setData($token);
$modelStatus->setStatus(ModelStatus::STATUS_SUCCESS);
$this->mailer->send($registrationMessage);
$message = Swift_Message::newInstance()
->setSubject('Please confirm your registration')
->setFrom('symphotest#openmailbox.org')
->setTo($email)
->setBody($this->twig->//->renderView('emails/confirm.html.twig',array('token'=>$data['data'])))
->addPart(
$this->renderView('emails/registration.txt.twig',array('token'=>$data['data'])),
'text/plain'
);
$this->get('mailer')->send($message);
}
catch(InvalidArgumentException $arg)
{
$modelStatus->setStatus(ModelStatus::STATUS_FAILURE);
$modelStatus->setMessage($arg->getMessage());
}
catch (\Exception $e)
{
$modelStatus->setStatus(ModelStatus::STATUS_FAILURE);
$modelStatus->setMessage($e->getMessage());
}
return $modelStatus;
}
}
And I am refactoring the following section:
$message = \Swift_Message::newInstance()
->setSubject('Please confirm your registration')
->setFrom('symphotest#openmailbox.org')
->setTo($email)
->setBody($this->renderView('emails/confirm.html.twig',array('token'=>$data['data'])))
->addPart(
$this->renderView('emails/registration.txt.twig',array('token'=>$data['data'])),
'text/plain'
);
$this->get('mailer')->send($message);
Into the Model method register.
But As you can see I render some twig templates and I do know the best Option on how to do it. So far I thought the following options:
To render the templates as string and pass them to the the register method, create and send the email there.
Load the twig rendering service into the model and the render into the model. If not exists create one.
In the second bullet I may need to load the Twig rendering engine into a service. How can I do that?
In the end having the constructor like this:
public function __construct(EntityManager $em, \Swift_Mailer $mailer,\Twig_Environment $twig)
{
$this->em=$em;
$this->mailer=$mailer;
$this->twig=$twig;
}
And loading the service like this:
user_model:
class: AppBundle\Models\UserModel
arguments: ['#doctrine.orm.entity_manager','#mailer','#twig']
Seems that solved the problem.

Automatically merge session user in Symfony2

I have written my own User-class extending Symfony's UserInterface and EquatableInterface which gets authenticated nice on logins and is correctly retrievable using $this->getUser(); in a controller.
Now, my question is, if it is possible to write something (dunno, a listener for example) that can automatically merge the user coming from the open session (so the one you retrieve with $user = $this->getUser();), so I dont have to call stuff like:
/**
* #Route("/url/to/route")
*/
public function myAction()
{
$user = $this->getUser();
$mergedUser = $this->getDoctrine()->getManager()->merge($user);
return array('user' => $mergedUser);
}
But instead:
/**
* #Route("/url/to/route")
*/
public function myAction()
{
/* User gets merged automatically! */
$mergedUser = $this->getUser();
return array('user' => $mergedUser);
}

J2ME Back command - returning to previous screen

I'm stuck trying to figure out how to create a back command to the previous screen.The page I'm trying to return to does not have a form but a List but when I set the 'back' command listener to the list it just seems to throw a null pointer exception.
Here is my main class
import java.util.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;
/**
*
*/
public class CalFrontEnd extends MIDlet implements CommandListener
{
private Display display;
protected List list = new List("Please Select a Option", List.IMPLICIT);
private Command select = new Command("Select", Command.SCREEN, 1);
private Command exit = new Command("Exit", Command.EXIT, 2);
private Command save = new Command("Save,", Command.SCREEN, 2);
private DateField calendar;
/**
*
*/
public CalFrontEnd()
{
display = Display.getDisplay(this);
list.append("Select Date", null);
list.append("Add Events", null);
list.append("Remove Events", null);
list.append("Browse Events", null);
list.addCommand(select);
list.addCommand(exit);
list.setCommandListener(this);
}
/**
* Start Application
*/
public void startApp()
{
display.setCurrent(list);
}
/**
* Pause Application Method
*/
public void pauseApp()
{}
/**
* Destroy Application Method
*/
public void destroyApp(boolean unconditional)
{}
/**
*
* #param command
* #param displayable
*/
public void commandAction(Command command, Displayable displayable)
{
if (displayable == list) {
if (command == List.SELECT_COMMAND) {
switch (list.getSelectedIndex()) {
case 0: // select Date
SelectDate myDate = new SelectDate(display);
myDate.BuildCalendar();
break;
case 1: //add Events
AddEvents myAEvents = new AddEvents(display);
myAEvents.BuildAddEvents();
break;
case 2: //Remove Events
RemoveEvents myREvents = new RemoveEvents(display);
myREvents.BuildRemoveEvents();
break;
case 3: //Browse Events
BrowseEvents myBEvents = new BrowseEvents(display);
myBEvents.BuildBrowseEvents();
break;
}
} else if (command == exit) {
destroyApp(false);
notifyDestroyed();
}
}
}
}
And this is the class which I'm trying to use the back button on
import java.util.*;
import javax.microedition.lcdui.*;
/**
*
*/
public class SelectDate extends CalFrontEnd implements CommandListener
{
private DateField calendar;
private Form form = new Form("Please Select a Date");
private Command select = new Command("Select", Command.SCREEN, 1);
private Command back = new Command("Back", Command.BACK, 2);
private Command save = new Command("Save,", Command.SCREEN, 2);
private Display display;
/**
*
*/
public SelectDate(Display display)
{
this.display = display;
}
/**
*
*/
public void BuildCalendar()
{
calendar = new DateField("Date In :", DateField.DATE, TimeZone.getTimeZone("GMT"));
form.append(calendar);
form.addCommand(back);
form.setCommandListener(this);
display.setCurrent(form);
}
/**
*
* #param command
* #param displayable
*/
public void commandAction(Command command, Display display)
{
if (command == back)
{
display.setCurrent(list);
}
}
}
Inappropriate use of inheritance has brought you into trouble here. Look, there is a list field in SelectDate class but it is not visible in code, because it is inherited from superclass (extends CalFrontEnd and protected List list are where all your trouble really begins).
When you create an instance of SelectDate (new SelectDate(display)) this field is initialized with null - and you never change it after that. It's hard for you to notice that because the very declaration of list is buried in other file in superclass. And, which makes things even harder, compiler can't help you here because the field is visible to it and it believes things are OK.
You know, this is only a beginning of your troubles related to overuse of inheritance. Further down the road, more headaches are waiting to happen. Think for example of what would happen if you accidentally remove or rename commandAction in SelectDate? Compiler will think it's all-right - just because superclass has this method, too. You'll only notice that things went wrong in some misterious way when you run the code and find out that commands at select date screen stop responding or began doing weird things. Actually it would be safer to hide CommandListener for both classes just to avoid this kind mistakes but that was discussed in another question.
I strongly recommend to wipe out extends CalFrontEnd from SelectDate. That will help compiler help you to find various logical issues in your code.
As for list to show by Back command, you can for example pass it as additional constructor parameter, like as below:
public class SelectDate implements CommandListener // drop "extends CalFrontEnd"
{
// ...
private Display display;
private List list; // add the field for the list
public SelectDate(Display display, List list) // add list as parameter
{
this.display = display;
this.list = list; // initialize field
}
// ... commandAction code will get the right "list" now
}
There are a number of problems regarding your code.
One gnat has already mentioned (Remove extends CalFrontEnd in SelectData class).
Secondly you are not calling select command in commandAction of your code (command you are calling is List.SELECT_COMMAND which is not select). So change if (command == List.SELECT_COMMAND) to if (command == select).
Thirdly documentation of commandAction in CommandListener declares its second parameter to be Displayable while you are declaring it with Display.
the error is that there's no variable called list, the solution however is to simply change the code under your back button from
display.setCurrent(list)
to
display.setCurrent(CalFrontEnd.list)

Resources