I am using Play 2.0.4 and I'm doing a test unit for actors who make use of the database.
The test begins well, but then at a given moment the connection with the database is closed and the actor who is running fails.
Code:
public class ActorTest extends Helpers {
private FakeApplication app;
private ActorSystem actorSystem;
private ActorRef actorRef;
private BankAccount account;
#Before
public void initTest() {
Map<String, String> params = new HashMap<String, String>();
params.put("db.default.driver", "com.mysql.jdbc.Driver");
params.put("db.default.url", "mysql://root:XXXX#localhost/YYY");
params.put("ebean.default", "models.*");
app = fakeApplication(params);
actorSystem = play.api.libs.concurrent.Akka.system(app.getWrappedApplication());
}
#Test
public void updateAccountTransaction() {
running(app, new Runnable() {
#Override
public void run() {
account = BankAccount.find.byId(new Long(1));
actorRef = actorSystem.actorOf(new Props(new UntypedActorFactory() {
#Override
public UntypedActor create() {
return new AccountTaskActor(account);
}
}));
Calendar fromDate = Calendar.getInstance();
....
....
Calendar toDate = Calendar.getInstance();
final InputRangeDateMessage param = new InputRangeDateMessage(fromDate, toDate);
junit.framework.Assert.assertNotNull(account);
Future<Object> future = Patterns.ask(actorRef, param, 1000000);
Promise<Object> sdf = Akka.asPromise(future);
Promise<Result> r2 = sdf.map(new Function<Object, Result>() {
#Override
public Result apply(Object response) throws Throwable {
if (response instanceof ErrorMessage) {
ErrorMessage e = (ErrorMessage) response;
System.out.println("Error Message " + e.getErrorText());
junit.framework.Assert.assertEquals(e.getErrorCode(), -1);
} else if (response instanceof BankAccountMessage) {
BankAccount a = ((BankAccountMessage) response).getAccount();
System.out.println("BankAccount " + a.accountsLastUpdate);
}
return ok();
}
});
Result test2;
test2 = async(r2);
}
});
}
}
AFAIK, you have to wait for the end of your Promise:
...
Result test2 = r2.get();
Related
I was trying to get specific data from database but every time I'm getting the following error!
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to com.lglsys.entity.TDasProductDownload
So this is my QueryService class
#Dependent
public class QueryService {
List<TDasProductDownload> downloadLink = new ArrayList();
final private Logger logger =
LogManager.getLogger(QueryService.class.getName());
#PersistenceContext(unitName="DownloadServices")
EntityManager em;
public QueryService() { super(); }
public List<TDasProductDownload> findAllDownloadLinks() {
try {
downloadLink=
em.createQuery(queryForDownloadLinks,TDasProductDownload.class)
.getResultList();
return downloadLink;
} catch (Exception e) {
logger.info(e.toString());
return null;
}
}
}
program gives error in this class /
EndPoint class
public class PreControlWSEndPoint {
private Session session;
final private Logger logger = LogManager.getLogger(PreControlWSEndPoint.class.getName());
List<TDasProductDownload> downloadLink = new ArrayList();
#PersistenceContext(unitName="DownloadServices")
EntityManager em;
#Inject
QueryService service;
#OnOpen
public void Open(Session session) throws IOException, InterruptedException {
this.session = session;
this.sendMessage("Connection Oppened");
logger.info("EndPoint Opened");
try {
downloadLink = service.findAllDownloadLinks();
logger.info(downloadLink.size());
TDasProductDownload str = downloadLink.get(0);
logger.info(str.getDownloadStatus()); //**Eror line!!**
} catch (Exception e) {
logger.info(e.toString() + " .D");
}
}
#OnMessage
public void onMessage(String message) {}
#OnClose
public void Close() {}
}
I can't see what's happening in my code.
I fixed it!
public List<String> findAllDownloadLinks() {
try {
downloadLink=
em.createQuery(queryForDownloadLinks,String.class)
.getResultList();
return downloadLink;
} catch (Exception e) {
logger.info(e.toString());
return null;
}
}
then i can print like so
for(int temp=0;temp<=downloadLink.size();temp++){
logger.info(downloadLink.get(temp));
}
I've created a method that shall return a two-dimensional Array, everything works perfectly as the array is being correctly filled in the method's try.
But once I display the array on onCreate(), it's returning null.
public class ListTickets extends AppCompatActivity {
public String[][] ticketTab ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_tickets);
ticketTab = new String[Integer.valueOf(nbTicket)][nbTicketTab];
DisplayArray(getTicketsHTTP());
}
private String[][] getTicketsHTTP() {
final JsonObjectRequest getRequest = new JsonObjectRequest(Request.Method.GET, URL, null,
new Response.Listener<JSONObject>()
{
#Override
public void onResponse(JSONObject response) {
try {
JSONArray Jdata = response.getJSONArray("data");
for (int i=0; i < Jdata.length(); i++) {
try {
JSONObject oneTicket = Jdata.getJSONObject(i);
titreTicket = oneTicket.getString("1");
slaTicket = oneTicket.getString("30");
dateDebutTicket = oneTicket.getString("15");
urgenceTicket = oneTicket.getString("10");
statutTicket = oneTicket.getString("12");
idTicket = oneTicket.getString("2");
} catch (JSONException e) {
Log.e("Err", e.getMessage());
}
ticketTab[i][0] = titreTicket;
ticketTab[i][1] = slaTicket;
ticketTab[i][2] = dateDebutTicket;
ticketTab[i][3] = urgenceText(urgenceTicket);
ticketTab[i][4] = calculTempsRestant(dateDebutTicket, slaTicket, dateEchanceTicket);
ticketTab[i][5] = String.valueOf(ticketEnretard);
ticketTab[i][6] = statutTicket;
ticketTab[i][7] = idTicket;
}
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener()
{
#Override
public void onErrorResponse(VolleyError error) {
Log.e("Error.Response", error.toString());
}
}
){
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> params = new HashMap<String, String>();
params.put("App-Token",FirstEverActivity.App_Token);
params.put("Session-Token",session_token);
return params;
}
};
// add it to the RequestQueue
queue.add(getRequest);
return ticketTab;
}
}
I declared ticketTab outside the onCreate because when I declare it inside the method, I cannot change it inside the try.
How can I return the array correctly?
In your onCreate you are using this line:
ticketTab = new String[Integer.valueOf(nbTicket)][nbTicketTab];
and those values, nbTicket and nbTicketTab are not declared anywhere in your code, maybe that's why they are returning null, you have to initialize them and asign values.
I had been developing and testing on the Codename One simulator and everything worked fine.
However, when I tested it on a real Android device, I get a 405 Method Not Allowed error. This happened on both a POST and GET request.
I suspect it is the #Consume and #Produces which are causing the problem. How do I fix this?
Here are my server side code:
#GET
#Path("/all/{language}")
#Produces("application/json")
public final Response getAllCelebrities(#PathParam("language") String language) {
String celebritiesJSONString = CelebrityActions.getAllCelebritiesNamesJSONString(language);
return Response.ok(celebritiesJSONString).build();
}
#POST
#Path("/login")
#Consumes("application/x-www-form-urlencoded")
#Produces("text/plain")
public final Response login(
#FormParam("loginid") String loginid,
#FormParam("password") String password
) {
System.out.println("login 0 started");
Long fanID;
try {
fanID = AccountsActions.login(loginid, password);
} catch (Exception e) {
return Response.serverError().entity(e.getMessage()).build();
}
if (fanID == null) {
return responseFanIDNotFoundError();
}
System.out.println("This is printed out!!!");
System.out.println("login 100 ended");
return Response.ok().build();
}
And here's my log upon execution of the login() method:
login 0 started
This is printed out!!!
login 100 ended
which means the server side method was ready to return a 200 response.
What is causing the Android client to show a 405 Method Not Allow error?
EDIT: I'm adding my cient-side code here:
(note that this one handles a cookie from a server)
public class Login extends PostConnection {
private final String LoginEndpoint = "account/login";
private String loginIDString;
private String loginPasswordString;
// Tested and works on simulator!
public Login(String loginIDString, String loginPasswordString) {
super();
endpoint = LoginEndpoint;
this.loginIDString = loginIDString;
this.loginPasswordString = loginPasswordString;
}
#Override
protected void prepareParametersMap() {
parametersMap = new HashMap<>();
parametersMap.put("loginid", loginIDString);
parametersMap.put("password", loginPasswordString);
}
}
public abstract class PostConnection extends PostPutConnection {
public PostConnection() {
super();
}
public boolean connect() throws IOException {
connectionRequest.setHttpMethod("POST");
return super.connect();
}
}
public abstract class PostPutConnection extends Connection {
protected HashMap<String, String> parametersMap;
public PostPutConnection() {
super();
}
protected static final void setPostParameters(ConnectionRequest connectionRequest, HashMap<String, String> parametersMap) {
Set<String> paramateterKeys = parametersMap.keySet();
Iterator<String> parameterKeysIterator = paramateterKeys.iterator();
while (parameterKeysIterator.hasNext()) {
String key = parameterKeysIterator.next();
String value = parametersMap.get(key);
connectionRequest.addArgument(key, value);
}
}
protected abstract void prepareParametersMap();
public boolean connect() throws IOException {
prepareParametersMap();
setPost();
setPostParameters();
return super.connect();
}
private void setPostParameters() {
setPostParameters(connectionRequest, parametersMap);
}
private final void setPost() {
connectionRequest.setPost(true);
}
}
public abstract class Connection {
private final static String protocol = "http";
private final static String domain = "192.168.0.109:20000";
protected ConnectionRequest connectionRequest;
protected String endpoint;
public Connection() {
super();
init();
}
protected void init() {
connectionRequest = new ConnectionRequest();
connectionRequest.setCookiesEnabled(true);
ConnectionRequest.setUseNativeCookieStore(true);
}
public boolean connect() throws IOException {
connectionRequest.setUrl(protocol + "://" + domain + "/" + endpoint);
NetworkManager.getInstance().addToQueueAndWait(connectionRequest);
int responseCode = getResponseCode();
return responseCode == 200 ? true : false;
}
private int getResponseCode() {
int responseCode = connectionRequest.getResponseCode();
return responseCode;
}
}
And another method below:
(note that this one does not handle cookies)
public class GetAllCelebrities extends GetConnection {
private final String GetCelebritiesEndpoint = "celebrity/all";
public GetAllCelebrities(String language) {
super();
endpoint = GetCelebritiesEndpoint + "/" + language;
}
}
public abstract class GetConnection extends Connection {
private Map<String, Object> responseData;
public GetConnection() {
super();
}
public boolean connect() throws IOException {
connectionRequest.setHttpMethod("GET");
boolean connectResult = super.connect();
if (!connectResult) {
return false;
}
responseData = getResponseResult();
return true;
}
private Map<String, Object> getResponseResult() throws IOException {
byte[] responseData = connectionRequest.getResponseData();
ByteArrayInputStream responseDataBAIS = new ByteArrayInputStream(responseData);
InputStreamReader responseDataISR = new InputStreamReader(responseDataBAIS, "UTF-8");
JSONParser responseDateJSONParser = new JSONParser();
Map<String, Object> responseResult = responseDateJSONParser.parseJSON(responseDataISR);
return responseResult;
}
public Map<String, Object> getResponseData() {
return responseData;
}
}
And it is called like:
private Map<String, Object> fetchCelebrities() throws IOException {
GetAllCelebrities getAllCelebrities = new GetAllCelebrities("en");
getAllCelebrities.connect();
return getAllCelebrities.getResponseData();
}
private boolean performLogin() throws IOException {
String loginIDString = loginID.getText();
String loginPasswordString = loginPassword.getText();
Login login = new Login(loginIDString, loginPasswordString);
boolean loginResult = login.connect();
return loginResult;
}
It's a bit hard to read all of this code but I'll venture a guess based on the server message. You've set the method to "PUT" along the way in the post put class and that isn't supported by the server yet.
The best way to debug these things is with the network monitor in the Simulator. Its shows the traffic and would have made these things mostly clear
I am trying to access GAE Memcache and Datastore APIs from Dataflow.
I have followed How to use memcache in dataflow? and setup Remote API https://cloud.google.com/appengine/docs/java/tools/remoteapi
In my pipeline I have written
public static void main(String[] args) throws IOException {
RemoteApiOptions remApiOpts = new RemoteApiOptions()
.server("xxx.appspot.com", 443)
.useApplicationDefaultCredential();
RemoteApiInstaller installer = new RemoteApiInstaller();
installer.install(remApiOpts);
try {
DatastoreConfigManager2.registerConfig("myconfig");
final String topic = DatastoreConfigManager2.getString("pubsub.topic");
final String stagingDir = DatastoreConfigManager2.getString("dataflow.staging");
...
bqRows.apply(BigQueryIO.Write
.named("Insert row")
.to(new SerializableFunction<BoundedWindow, String>() {
#Override
public String apply(BoundedWindow window) {
// The cast below is safe because CalendarWindows.days(1) produces IntervalWindows.
IntervalWindow day = (IntervalWindow) window;
String dataset = DatastoreConfigManager2.getString("dataflow.bigquery.dataset");
String tablePrefix = DatastoreConfigManager2.getString("dataflow.bigquery.tablenametemplate");
String dayString = DateTimeFormat.forPattern("yyyyMMdd")
.print(day.start());
String tableName = dataset + "." + tablePrefix + dayString;
LOG.info("Writing to BigQuery " + tableName);
return tableName;
}
})
where DatastoreConfigManager2 is
public class DatastoreConfigManager2 {
private static final DatastoreService DATASTORE = DatastoreServiceFactory.getDatastoreService();
private static final MemcacheService MEMCACHE = MemcacheServiceFactory.getMemcacheService();
static {
MEMCACHE.setErrorHandler(ErrorHandlers.getConsistentLogAndContinue(Level.INFO));
}
private static Set<String> configs = Sets.newConcurrentHashSet();
public static void registerConfig(String name) {
configs.add(name);
}
private static class DatastoreCallbacks {
// https://cloud.google.com/appengine/docs/java/datastore/callbacks
#PostPut
public void updateCacheOnPut(PutContext context) {
Entity entity = context.getCurrentElement();
if (configs.contains(entity.getKind())) {
String id = (String) entity.getProperty("id");
String value = (String) entity.getProperty("value");
MEMCACHE.put(id, value);
}
}
}
private static String lookup(String id) {
String value = (String) MEMCACHE.get(id);
if (value != null) return value;
else {
for (String config : configs) {
try {
PreparedQuery pq = DATASTORE.prepare(new Query(config)
.setFilter(new FilterPredicate("id", FilterOperator.EQUAL, id)));
for (Entity entity : pq.asIterable()) {
value = (String) entity.getProperty("value"); // use last
}
if (value != null) MEMCACHE.put(id, value);
} catch (Exception e) {
e.printStackTrace();
}
}
}
return value;
}
public static String getString(String id) {
return lookup(id);
}
}
When my pipeline runs on Dataflow I get the exception
Caused by: java.lang.NullPointerException
at com.google.appengine.api.NamespaceManager.get(NamespaceManager.java:101)
at com.google.appengine.api.memcache.BaseMemcacheServiceImpl.getEffectiveNamespace(BaseMemcacheServiceImpl.java:65)
at com.google.appengine.api.memcache.AsyncMemcacheServiceImpl.doGet(AsyncMemcacheServiceImpl.java:401)
at com.google.appengine.api.memcache.AsyncMemcacheServiceImpl.get(AsyncMemcacheServiceImpl.java:412)
at com.google.appengine.api.memcache.MemcacheServiceImpl.get(MemcacheServiceImpl.java:49)
at my.training.google.common.config.DatastoreConfigManager2.lookup(DatastoreConfigManager2.java:80)
at my.training.google.common.config.DatastoreConfigManager2.getString(DatastoreConfigManager2.java:117)
at my.training.google.mss.pipeline.InsertIntoBqWithCalendarWindow$1.apply(InsertIntoBqWithCalendarWindow.java:101)
at my.training.google.mss.pipeline.InsertIntoBqWithCalendarWindow$1.apply(InsertIntoBqWithCalendarWindow.java:95)
at com.google.cloud.dataflow.sdk.io.BigQueryIO$Write$Bound$TranslateTableSpecFunction.apply(BigQueryIO.java:1496)
at com.google.cloud.dataflow.sdk.io.BigQueryIO$Write$Bound$TranslateTableSpecFunction.apply(BigQueryIO.java:1486)
at com.google.cloud.dataflow.sdk.io.BigQueryIO$TagWithUniqueIdsAndTable.tableSpecFromWindow(BigQueryIO.java:2641)
at com.google.cloud.dataflow.sdk.io.BigQueryIO$TagWithUniqueIdsAndTable.processElement(BigQueryIO.java:2618)
Any suggestions? Thanks in advance.
EDIT: my functional requirement is building a pipeline with some configurable steps based on datastore entries.
I am trying to use OKHTTP (version 2.4.0) along retrofit (1.9.0) on google app engine (1.9.22).
Here is the how i use it:
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setConnectTimeout(COMPOSER_MODULE_CONNECTION_TIMEOUT, TimeUnit.SECONDS);
okHttpClient.setReadTimeout(COMPOSER_MODULE_SOCKET_TIMEOUT, TimeUnit.SECONDS);
RestAdapter restAdapter = new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.FULL)
.setConverter(new JacksonConverter())
.setEndpoint(ENDPOINT_PATH)
.setClient(new OkClient(okHttpClient))
.build();
This throws the following error:
java.lang.NoClassDefFoundError: java.net.ProxySelector is a restricted class. Please see the Google App Engine developer's guide for more details.
at com.google.apphosting.runtime.security.shared.stub.java.net.ProxySelector.<clinit>(ProxySelector.java)
at com.squareup.okhttp.OkHttpClient.copyWithDefaults(OkHttpClient.java:614)
at com.squareup.okhttp.Call.<init>(Call.java:50)
at com.squareup.okhttp.OkHttpClient.newCall(OkHttpClient.java:595)
at retrofit.client.OkClient.execute(OkClient.java:53)
I gather from the error that "java.net.ProxySelector" is not white-listed for use on google appengine.
Question 1)
Is it possible to use OKHTTP (version 2.4.0) along retrofit (1.9.0) on google app engine (1.9.22)? i.e, is there a work around for this error
if not,
Question 2)
Are there any other way to:
(a) use async HTTP calls with google appengine (with URLFetchService, for instance) ?
(b) set connection and socket timeouts for the client used from (a) ?
The links i have come across via search:
(1) Retrofit timeout configuration for clients
(2) Google App Engine URL Fetch Java API
You can use HttpUrlConnection with Retrofit2 to use it in Google APP Engine
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.servlet.http.HttpServletResponse;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.Protocol;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.BufferedSink;
import okio.BufferedSource;
import okio.Okio;
public class RetrofitCall implements Call {
Request request;
RetrofitCall(Request request) {
this.request = request;
}
#Override
public Request request() {
return request;
}
#Override
public Response execute() throws IOException {
URL url = request.url().url();
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setUseCaches(false);
connection.setDoOutput(true);
connection.setRequestMethod(request.method());
Headers headers = request.headers();
if (headers != null) {
for (int i = 0; i < headers.size(); i++) {
String name = headers.name(i);
connection.setRequestProperty(name, headers.get(name));
}
}
if (request.body() != null) {
BufferedSink outbuf;
outbuf = Okio.buffer(Okio.sink(connection.getOutputStream()));
request.body().writeTo(outbuf);
outbuf.close();
}
connection.connect();
final BufferedSource source = Okio.buffer(Okio.source(connection.getInputStream()));
if (connection.getResponseCode() != HttpServletResponse.SC_OK) {
throw new IOException("Fail to call " + " :: " + source.readUtf8());
}
Response response = new Response.Builder()
.code(connection.getResponseCode())
.message(connection.getResponseMessage())
.request(request)
.protocol(Protocol.HTTP_1_1)
.body(new ResponseBody() {
#Override
public MediaType contentType() {
return MediaType.parse(connection.getContentType());
}
#Override
public long contentLength() {
return connection.getContentLengthLong();
}
#Override
public BufferedSource source() {
return source;
}
})
.build();
return response;
}
#Override
public void enqueue(Callback responseCallback) {
}
#Override
public void cancel() {
}
#Override
public boolean isExecuted() {
return false;
}
#Override
public boolean isCanceled() {
return false;
}
public static class Factory implements Call.Factory {
#Override
public Call newCall(Request request) {
return new RetrofitCall(request);
}
}
}
You can use the following code snippet to run Retorifit2 with GAE limitations. It contains a lot of debugging stuffs free to remove in production and does not implement real async call.
okhttp3.Call.Factory gaeCallFactory = new okhttp3.Call.Factory() {
#Override
public okhttp3.Call newCall(final Request request) {
final URL url = request.url().url();
final String method = url.toString();
return new okhttp3.Call() {
#Override
public Request request() {
return request;
}
#Override
public Response execute() throws IOException {
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setUseCaches(false);
if (request.body() != null) {
//TODO ajust for different needs
connection.setRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
BufferedSink outbuf;
ByteArrayOutputStream out = new ByteArrayOutputStream();
outbuf = Okio.buffer(Okio.sink(out));
request.body().writeTo(outbuf);
outbuf.close();
logger.info("Calling " + method + "\n" + new String(out.toByteArray()));
outbuf = Okio.buffer(Okio.sink(connection.getOutputStream()));
request.body().writeTo(outbuf);
outbuf.close();
} else {
logger.info("Calling " + method);
}
final BufferedSource source = Okio.buffer(Okio.source(connection.getInputStream()));
if (connection.getResponseCode() != HttpServletResponse.SC_OK) {
throw new IOException("Fail to call " + method + " :: " + source.readUtf8());
}
Response response = new Response.Builder()
.code(connection.getResponseCode())
.message(connection.getResponseMessage())
.request(request)
.protocol(Protocol.HTTP_1_1)
.body(new ResponseBody() {
#Override
public MediaType contentType() {
return MediaType.parse(connection.getContentType());
}
#Override
public long contentLength() {
return connection.getContentLengthLong();
}
#Override
public BufferedSource source() {
return source;
}
})
.build();
logger.info("Call response code: " + response.code() + " message: " + response.message());
return response;
}
#Override
public void enqueue(Callback responseCallback) {
try {
responseCallback.onResponse(this, execute());
} catch (IOException e) {
responseCallback.onFailure(this, e);
}
}
#Override
public void cancel() {
}
#Override
public boolean isExecuted() {
return false;
}
#Override
public boolean isCanceled() {
return false;
}
};
}
};
Retrofit retrofit = new Retrofit.Builder()
.callFactory(gaeCallFactory)
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(ENDPOINT_URI)
.build();
You need to use the Appengine URLFetchClient instead of the OkHttpClient. Like this:
import retrofit.appengine.UrlFetchClient;
RestAdapter restAdapter = new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.FULL)
.setConverter(new JacksonConverter())
.setEndpoint(ENDPOINT_PATH)
.setClient(new UrlFetchClient())
.build();
Please note this only works with Retrofit1, this will not work with Retrofit2 because it's coupled directly to OkHttp as explained by Jake Wharton here