react native android pos inbuilt printer integration - java

hi guys i have been trying to integrate sdk of an android pos machine which comes with inbult printer to my react native app.Since the sdk is native i use bridging . But i am not able to print the data even after i follow the documents .
leaving the code i tried
import android.content.res.AssetManager;
import android.printservice.PrintService;
import android.provider.Settings;
import android.text.Layout;
import android.widget.Toast;
import androidx.annotation.NonNull;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.zcs.sdk.DriverManager;
import com.zcs.sdk.Printer;
import com.zcs.sdk.SdkResult;
import com.zcs.sdk.print.PrnStrFormat;
import com.zcs.sdk.print.PrnTextFont;
import com.zcs.sdk.print.PrnTextStyle;
import com.zcs.sdk.util.LogUtils;
import java.io.IOException;
import java.io.InputStream;
public class CustomModule extends ReactContextBaseJavaModule {
private static ReactApplicationContext reactContext;
DriverManager mDriverManager= DriverManager.getInstance();
Printer mPrinter = mDriverManager.getPrinter();
CustomModule(ReactApplicationContext context) {
super(context);
reactContext = context;
}
#ReactMethod
public void show() {
int printStatus = mPrinter.getPrinterStatus();
System.out.println(mPrinter);
PrnStrFormat format = new PrnStrFormat();
format.setTextSize(30);
mPrinter.setPrintAppendString(" -----------------------------", format);
mPrinter.setPrintAppendString(" ", format);
mPrinter.setPrintAppendString(" ", format);
mPrinter.setPrintAppendString(" ", format);
mPrinter.setPrintAppendString(" ", format);
printStatus = mPrinter.setPrintStart();
Toast.makeText(reactContext, "Hi from Android"+"here", Toast.LENGTH_LONG).show();
}
#ReactMethod
public void getDeviceId(Promise promise) {
try {
String android_id = Settings.Secure.getString(reactContext.getContentResolver(),
Settings.Secure.ANDROID_ID);
promise.resolve(android_id);
} catch (Exception e) {
promise.reject("Error", e);
}
}
#NonNull
#Override
public String getName() {
return "ABC";
}
}
please let know if anyone has an idea

Related

androidx.test.espresso.NoMatchingRootException: Matcher 'is toast' did not match any of the following roots:

Recently I had a problem with JUnit Testing of a Toast.
In my LoginActivity class I have a Button with that calls this:
Toast.makeText(LoginActivity.this, "toast text", Toast.LENGTH_SHORT).show();
And this is a LoginActivityTest class
package com.android_pokladna.LoginActivity;
import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.test.core.app.ActivityScenario;
import androidx.test.espresso.UiController;
import androidx.test.espresso.ViewAction;
import androidx.test.rule.ActivityTestRule;
import com.android_pokladna.Model.Login.LoginRequest;
import com.android_pokladna.Model.Login.LoginResponse;
import com.android_pokladna.Other.TokenSaver;
import com.android_pokladna.R;
import com.android_pokladna.ShopActivity.ShopActivity;
import com.android_pokladna.api.ApiClientandService.ApiCallback;
import com.android_pokladna.api.ApiClientandService.ApiClient;
import org.hamcrest.Matcher;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import java.util.concurrent.TimeUnit;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.typeText;
import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.RootMatchers.isDialog;
import static androidx.test.espresso.matcher.RootMatchers.isFocusable;
import static androidx.test.espresso.matcher.RootMatchers.isPlatformPopup;
import static androidx.test.espresso.matcher.RootMatchers.withDecorView;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static androidx.test.internal.runner.junit4.statement.UiThreadStatement.runOnUiThread;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.*;
public class LoginActivityTest {
#Rule
public ActivityTestRule<LoginActivity> activityTestRule = new ActivityTestRule(LoginActivity.class);
private LoginActivity loginActivity = null;
public static ViewAction waitFor(final long millis) {
return new ViewAction() {
#Override
public Matcher<View> getConstraints() {
return isRoot();
}
#Override
public String getDescription() {
return "Wait for " + millis + " milliseconds.";
}
#Override
public void perform(UiController uiController, final View view) {
uiController.loopMainThreadForAtLeast(millis);
}
};
}
#Before
public void setUp() throws Exception {
loginActivity = activityTestRule.getActivity();
//clears all system dialogs
loginActivity.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
}
#Test
public void testDialogButtonClick() throws Throwable {
onView(withId(R.id.activityLoginButtonEnter)).perform(click());
onView(withId(R.id.activityLoginDialogButton)).perform(click());
onView(withText("TEXT")).inRoot(new ToastMatcher())
.check(matches(withText("TEXT")));
}
#After
public void tearDown() throws Exception {
loginActivity = null;
}
}
The problem is that this part of the code:
onView(withText("toast text")).inRoot(new ToastMatcher())
.check(matches(withText("toast text")));
throws an error:
androidx.test.espresso.NoMatchingRootException: Matcher 'is toast' did not match any of the following roots: [Root{application-window-token=android.view.ViewRootImpl$W#a78c87f, window-token=android.view.ViewRootImpl$W#a78c87f, has-window-focus=true, layout-params-type=2, layout-params-string={(0,0)(wrapxwrap) gr=CENTER sim={adjust=pan} ty=APPLICATION fmt=TRANSPARENT wanim=0x10302ff
fl=DIM_BEHIND SPLIT_TOUCH HARDWARE_ACCELERATED
fitTypes=STATUS_BARS NAVIGATION_BARS CAPTION_BAR}, decor-view-string=DecorView{id=-1, visibility=VISIBLE, width=1144, height=1300, has-focus=false, has-focusable=true, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params={(0,0)(wrapxwrap) gr=CENTER sim={adjust=pan} ty=APPLICATION fmt=TRANSPARENT wanim=0x10302ff
fl=DIM_BEHIND SPLIT_TOUCH HARDWARE_ACCELERATED
fitTypes=STATUS_BARS NAVIGATION_BARS CAPTION_BAR}, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1}}, Root{application-window-token=android.view.ViewRootImpl$W#3be404c, window-token=android.view.ViewRootImpl$W#3be404c, has-window-focus=false, layout-params-type=1, layout-params-string={(0,0)(fillxfill) sim={adjust=pan} ty=BASE_APPLICATION wanim=0x10302fe
fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND FIT_INSETS_CONTROLLED
fitSides=}, decor-view-string=DecorView{id=-1, visibility=VISIBLE, width=2560, height=1600, has-focus=false, has-focusable=true, has-window-focus=false, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params={(0,0)(fillxfill) sim={adjust=pan} ty=BASE_APPLICATION wanim=0x10302fe
fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
pfl=FORCE_DRAW_STATUS_BAR_BACKGROUND FIT_INSETS_CONTROLLED
fitSides=}, tag=null, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=3}}]
at dalvik.system.VMStack.getThreadStackTrace(Native Method)
at java.lang.Thread.getStackTrace(Thread.java:1736)
at androidx.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:12)
at androidx.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:7)
at androidx.test.espresso.ViewInteraction.waitForAndHandleInteractionResults(ViewInteraction.java:8)
at androidx.test.espresso.ViewInteraction.check(ViewInteraction.java:12)
at com.android_pokladna.LoginActivity.LoginActivityTest.testDialogButtonClick(LoginActivityTest.java:116)
Tests ran to completion.
In the test class I use ToastMatcher class which looks like this:
package com.android_pokladna.LoginActivity;
import android.os.IBinder;
import android.view.WindowManager;
import androidx.test.espresso.Root;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
public class ToastMatcher extends TypeSafeMatcher<Root> {
/*
Author: http://www.qaautomated.com/2016/01/how-to-test-toast-message-using-espresso.html
*/
#Override public void describeTo(Description description) {
description.appendText("is toast");
}
#Override public boolean matchesSafely(Root root) {
int type = root.getWindowLayoutParams().get().type;
if ((type == WindowManager.LayoutParams.TYPE_TOAST)) {
IBinder windowToken = root.getDecorView().getWindowToken();
IBinder appToken = root.getDecorView().getApplicationWindowToken();
if (windowToken == appToken) {
return true;
}
}
return false;
}
}
I already saw that many people have similar problem. I did this according to one video where test is successfully done: https://www.youtube.com/watch?v=L037q8MGkGA&ab_channel=CodingWithMitch
His videos are really helpful but I don't understand the error I am getting.
The test takes a while to complete and when toast is getting tested. It is already gone and maybe that is why it is throwing an error.
If anyone could help me, I would really appreciate that. Thank you for your help!
I also have the same error related to inRoot here, so I used another solution to assert a toast message, replacing inRoot and ToastMatcher class by this solution with UIAutomator and assertTrue:
import androidx.test.platform.app.InstrumentationRegistry
import junit.framework.Assert.assertTrue
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice
val device: UiDevice
get() = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
assertTrue(device.hasObject(By.text(toastMessageDuplicated)))

Why can I not access this method from another class?

I have an Android app where I'm trying to make a GET request to my API using Retrofit2. I have copied some code online that allows me to add the access token to the body of the request as this is how my API is setup. Following the code online, the author is able to call the api variable from a different class but I am unable to.
Here is the class the api variable is defined:
cCustomerService.java
package com.example.dentdevils.helper.retrofit.oauth2.client;
import android.content.Context;
import android.content.SharedPreferences;
import com.example.dentdevils.helper.retrofit.oauth2.OauthConstant;
import com.example.dentdevils.helper.retrofit.oauth2.service.CustomerService;
import java.io.IOException;
import okhttp3.FormBody;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.Buffer;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.GET;
import static com.example.dentdevils.MainActivity.access;
import static com.example.dentdevils.MainActivity.mypreference;
public class cCustomerService {
public final CustomerService api;
private Context mContext;
SharedPreferences sharedPreferences;
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request.Builder requestBuilder = request.newBuilder();
mContext.getSharedPreferences(mypreference, Context.MODE_PRIVATE);
RequestBody formBody = new FormBody.Builder()
.add("access_token", sharedPreferences.getString(access, ""))
.build();
String postBodyToString = bodyToString(request.body());
postBodyToString += ((postBodyToString.length() > 0) ? "&" : "") + bodyToString(formBody);
request = requestBuilder.post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded;charset=UTF-8"), postBodyToString))
.build();
return chain.proceed(request);
}
}).build();
public static String bodyToString(final RequestBody requestBody) {
try {
final RequestBody copy = requestBody;
final Buffer buffer = new Buffer();
if (copy != null) {
copy.writeTo(buffer);
} else {
return "";
}
return buffer.readUtf8();
} catch (IOException e) {
return "didn't work";
}
}
public cCustomerService() {
Retrofit retrofit = new Retrofit.Builder()
.client(client)
.baseUrl(OauthConstant.DATA_SERVER_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
api = retrofit.create(CustomerService.class);
}
}
As you can see I set the api variables value at the bottom.
Now I want to access it in the following class:
ViewCustomers.Java
package com.example.dentdevils;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import com.example.dentdevils.helper.retrofit.oauth2.OauthConstant;
import com.example.dentdevils.helper.retrofit.oauth2.client.cCustomerService;
import com.example.dentdevils.helper.retrofit.oauth2.response.CustomerResponse;
import com.example.dentdevils.helper.retrofit.oauth2.service.CustomerService;
import java.io.IOException;
import java.util.List;
import okhttp3.FormBody;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import static com.example.dentdevils.MainActivity.access;
import static com.example.dentdevils.MainActivity.mypreference;
import static com.example.dentdevils.helper.retrofit.oauth2.client.cCustomerService.bodyToString;
public class ViewCustomers extends AppCompatActivity {
private Context mContext;
SharedPreferences sharedPreferences;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_customers);
CustomerService customerService = api.create(CustomerService.class);
Call<List<CustomerResponse>> callArray = customerService.getCustomers();
callArray.enqueue(new Callback<List<CustomerResponse>>() {
#RequiresApi(api = Build.VERSION_CODES.N)
#Override
public void onResponse(Call<List<CustomerResponse>> call, retrofit2.Response<List<CustomerResponse>> response) {
if (response.isSuccessful())
{
List<CustomerResponse> customers = response.body();
customers.forEach(customer -> System.out.println(customer.getName()));
} else {
Log.e("TAG", "Failed!");
}
}
#Override
public void onFailure(Call<List<CustomerResponse>> call, Throwable t) {
Log.e("TAG", t.getLocalizedMessage());
}
});
}
}
As you can see I reference the api variable on this line CustomerService customerService = api.create(CustomerService.class); but I get an error saying it cannot resolve symbol 'api'. Like I said the author of the post has his setup exactly like mine so why isn't mine working? I added the relevant imports and I still can't access it. Any help would be appreciated.

Spring JPA CrudRepository Autowired object is null when used with Apache Commons Tailer

I'm working on a small app that I can point to an Apache HTTP server log, follow the log (a la 'tail -f' in Linux), and write entries to an Oracle Database table.
I set up Spring Boot / Spring Data JPA application and created classes for my Entity, the CrudRepository interface, a service for the interface (though I believed this technically unnecessary for this implementation), and a runner to kick the process off. I also set up the TailerListenerAdapter to do the lifting for the log file parsing. I will post all of this code below.
The problem is that I can write a test record to the database successfully prior to starting the Tailer listener. However, when the listener is running, the Autowired Service in the TailerListenerAdapter, is null and throws an exception.
java.lang.NullPointerException
at sbx.demo.logauditor.util.AccessListener.handle(AccessListener.java:49)
at org.apache.commons.io.input.Tailer.readLines(Tailer.java:525)
at org.apache.commons.io.input.Tailer.run(Tailer.java:457)
at sbx.demo.logauditor.LogAuditRunner.run(LogAuditRunner.java:40)
{... more stack trace ...}
Here are the classes used (I probably have some unnecessary annotations in there left from experimentation) -
LogAuditRunner.java
package sbx.demo.logauditor;
import java.io.File;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import javax.transaction.Transactional;
import org.apache.commons.io.input.Tailer;
import org.apache.commons.io.input.TailerListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import lombok.var;
import sbx.demo.logauditor.model.AccessRecord;
import sbx.demo.logauditor.service.AccessService;
import sbx.demo.logauditor.util.AccessListener;
#Component
public class LogAuditRunner implements CommandLineRunner {
#Autowired
AccessService accServ;
final String datePattern = "dd/MMM/yyyy:HH:mm:ss Z";
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(datePattern);
#Override
#Transactional
public void run(String... args) throws Exception {
// This test code works if uncommented
//LocalDateTime TS = LocalDateTime.from(formatter.parse("31/Jan/2020:14:28:32 -0500"));
//var logTest = new AccessRecord("10.154.103.2",Timestamp.valueOf(TS),"/cs/resources/layouts/Top%20Menus/Oracle/tree_T_collection_closed.gif","304");
//System.out.println("Testing repository with " + logTest.toString());
//accServ.save(logTest);
TailerListener listener = new AccessListener();
Tailer tailer = new Tailer(new File("D:\\access_log"), listener);
tailer.run();
}
}
AccessService.java
package sbx.demo.logauditor.service;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.stereotype.Service;
import sbx.demo.logauditor.model.AccessRecord;
import sbx.demo.logauditor.repository.AccessRepository;
#Service
#Configurable
public class AccessService {
#Autowired(required = true)
AccessRepository accessRepo;
public void save(AccessRecord ar) {
try {
System.out.println("Writing record to database: " + ar.toString());
accessRepo.save(ar);
} catch (Exception e) {
e.printStackTrace();
}
}
public List<AccessRecord> findAll() {
List<AccessRecord> recList = new ArrayList<AccessRecord>();
try {
System.out.println("Searching database for all access records");
for(AccessRecord ar : accessRepo.findAll()) {
recList.add(ar);
}
} catch (Exception e) {
e.printStackTrace();
}
return recList;
}
}
AccessRepository.java
package sbx.demo.logauditor.repository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import sbx.demo.logauditor.model.AccessRecord;
#Repository
public interface AccessRepository extends CrudRepository<AccessRecord, Long>{
}
AccessRecord.java
package sbx.demo.logauditor.model;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.sql.Timestamp;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;
#Entity
#Table(name="ACCESS_LOG")
#Data
public class AccessRecord {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", updatable = false, nullable = false)
private Long id;
#Column(name="PROXY_AGENT")
private String agent;
#Column(name="SOURCE_IP")
private String sourceip;
#Column(name="ACCESS_TS")
private Timestamp reqts;
#Column(name="URI")
private String requri;
#Column(name="HTTP_STATUS")
private String respcode;
public AccessRecord() {}
public AccessRecord(String source, Timestamp ts, String uri, String status) {
this.sourceip = source;
this.reqts = ts;
this.requri = uri;
this.respcode = status;
try {
InetAddress ip = InetAddress.getLocalHost();
String hostname = ip.getHostName();
this.agent = hostname;
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public String toString() {
String record = "Record: [" + agent + "] [" + sourceip + "] [" + reqts + "] [" + requri + "] [" + respcode + "]";
return record;
}
}
AccessListener.java
package sbx.demo.logauditor.util;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.transaction.Transactional;
import org.apache.commons.io.input.TailerListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import lombok.var;
import sbx.demo.logauditor.model.AccessRecord;
import sbx.demo.logauditor.repository.AccessRepository;
import sbx.demo.logauditor.service.AccessService;
#Component
public class AccessListener extends TailerListenerAdapter {
final String regex = "^(\\S+) (\\S+) (\\S+) " +
"\\[([\\w:/]+\\s[+\\-]\\d{4})\\] \"(\\S+)" +
" (\\S+)\\s*(\\S+)?\\s*\" (\\d{3}) (\\S+)";
final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
final String datePattern = "dd/MMM/yyyy:HH:mm:ss Z";
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(datePattern);
#Autowired
AccessService accServ;
#Override
#Transactional
public void handle(String line) {
LogRecorder lr = new LogRecorder();
try {
final Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
String IP = matcher.group(1);
//String TS = matcher.group(4);
String URL = matcher.group(6);
String STATUS = matcher.group(8);
LocalDateTime TS = LocalDateTime.from(formatter.parse(matcher.group(4)));
var ar = new AccessRecord(IP,Timestamp.valueOf(TS),URL,STATUS);
accServ.save(ar);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
And finally LogauditorApplication.java
package sbx.demo.logauditor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class LogauditorApplication {
public static void main(String[] args) {
SpringApplication.run(LogauditorApplication.class, args);
}
}
Side note, I noticed that if I manually instantiate the AccessService (instead of relying on Autowiring), I can invoke it, but then the NullPointerException happens on the Autowired AccessRepository interface. It's clear to me that it has to do with the Autowiring, I just am not understanding why.
I know that there are ways to follow and send logs via command line (this is going to run in a Linux environment) but I want to ensure that it is robust enough to, say, restart if it dies, handle log rollovers, etc. Also, I'm planning to write in some extra validation to ensure entries don't overlap (i.e. - in the event the application restarts and re-reads an entire file). But, I wanted to get it working first. I thought it would be straightforward since Tailer requires so little code, and I'm already comfortable with Spring.
I was able to get this working by passing the AccessService as a parameter for the AccessListener constructor. I then had to add the #Transactional annotation to the save method in the AccessService so that transactions would commit after each line was processed inside the thread.
New AccessListener.java
package sbx.demo.logauditor.util;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.io.input.TailerListenerAdapter;
import sbx.demo.logauditor.model.AccessRecord;
import sbx.demo.logauditor.service.AccessService;
public class AccessListener extends TailerListenerAdapter {
final String regex = "^(\\S+) (\\S+) (\\S+) " +
"\\[([\\w:/]+\\s[+\\-]\\d{4})\\] \"(\\S+)" +
" (\\S+)\\s*(\\S+)?\\s*\" (\\d{3}) (\\S+)";
final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
final String datePattern = "dd/MMM/yyyy:HH:mm:ss Z";
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(datePattern);
private AccessService accServ;
public AccessListener(AccessService as) {
this.accServ = as;
}
// #Autowired
// AccessService accServ;
#Override
public void handle(String line) {
try {
final Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
String IP = matcher.group(1);
String URL = matcher.group(6);
String STATUS = matcher.group(8);
LocalDateTime TS = LocalDateTime.from(formatter.parse(matcher.group(4)));
AccessRecord ar = new AccessRecord(IP,Timestamp.valueOf(TS),URL,STATUS);
accServ.save(ar);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

Java : Android : Retrofit 2 response code is 200, response.body is null

I am trying to build an Android App that implements a Collaborative Filtering Algorithm using Retrofit 2,Realm and The Movie Database API.
When making my Retrofit callback, onResponse returns a successful status code (200), but from logging I get that my response.body().getResults returns null. I'm in this pickle now and I can't get it to work.My ApiService seem to be working fine and I make other retrofit callbacks to get directors,movies by title,movies by release date.Anyways, here is some code snippets that might be helpful.
APIService.java
package com.yannis.thesis.movierecommendationapp.api;
import com.yannis.thesis.movierecommendationapp.models.DirectorResponse;
import com.yannis.thesis.movierecommendationapp.models.GenreResponse;
import com.yannis.thesis.movierecommendationapp.models.Movie;
import com.yannis.thesis.movierecommendationapp.models.MovieResponse;
import com.yannis.thesis.movierecommendationapp.models.PrimaryMovieInfo;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Path;
import retrofit2.http.Query;
public interface APIService {
#POST("/list")
Call<Movie> loadMovie();
#GET("movie/top_rated")
Call<MovieResponse> getTopRatedMovies(#Query("api_key") String apiKey);
#GET("movie/popular")
Call<MovieResponse> getPopularMovies(#Query("api_key") String apiKey);
#GET("movie/{id}")
Call<MovieResponse> getMovieDetails(#Path("id") int id, #Query("api_key") String apiKey);
#GET("search/movie")
Call<MovieResponse> getMovieByTitle(#Query("query") String title, #Query("api_key") String apiKey);
}
MovieResponse.java
package com.yannis.thesis.movierecommendationapp.models;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import java.util.List;
public class MovieResponse {
#SerializedName("page")
private Integer page;
#SerializedName("results")
private List<Movie> results;
#SerializedName("total_results")
private Integer totalResults;
#SerializedName("total_pages")
private Integer totalPages;
public Integer getPage() {
return page;
}
public void setPage(Integer page) {
this.page = page;
}
public List<Movie> getResults() {
return results;
}
public void setResults(List<Movie> results) {
this.results = results;
}
public Integer getTotalResults() {
return totalResults;
}
public void setTotalResults(Integer totalResults) {
this.totalResults = totalResults;
}
public Integer getTotalPages() {
return totalPages;
}
public void setTotalPages(Integer totalPages) {
this.totalPages = totalPages;
}
}
MovieRecommendationApp.java
package com.yannis.thesis.movierecommendationapp;
import android.app.Application;
import android.support.annotation.NonNull;
import android.support.v4.view.PagerAdapter;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
import com.luseen.logger.LogType;
import com.luseen.logger.Logger;
import com.weiwangcn.betterspinner.library.BetterSpinner;
import com.yannis.thesis.movierecommendationapp.activities.BaseActivity;
import com.yannis.thesis.movierecommendationapp.activities.MainActivity;
import com.yannis.thesis.movierecommendationapp.api.APIService;
import com.yannis.thesis.movierecommendationapp.models.DirectorResponse;
import com.yannis.thesis.movierecommendationapp.models.DirectorResult;
import com.yannis.thesis.movierecommendationapp.models.Genre;
import com.yannis.thesis.movierecommendationapp.models.GenreResponse;
import com.yannis.thesis.movierecommendationapp.models.MainPagerEnum;
import com.yannis.thesis.movierecommendationapp.models.Movie;
import com.yannis.thesis.movierecommendationapp.models.MovieResponse;
import com.yannis.thesis.movierecommendationapp.models.MovieRecommendedForUser;
import com.yannis.thesis.movierecommendationapp.models.Recommendation;
import com.yannis.thesis.movierecommendationapp.models.User;
import com.yannis.thesis.movierecommendationapp.models.UserRatesMovie;
import com.yannis.thesis.movierecommendationapp.MovieRecommendationApp;
import com.yannis.thesis.movierecommendationapp.R;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import io.realm.Realm;
import io.realm.RealmConfiguration;
import io.realm.RealmQuery;
import io.realm.RealmResults;
import io.realm.Sort;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Headers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class MovieRecommendationApp extends Application {
private static MovieRecommendationApp instance;
public BaseActivity lastActivity;
String API_BASE_URL = "http://api.themoviedb.org/3/";
private final static String API_KEY = "******************";
private static Retrofit retrofitinstance;
private String loggedInUserId;
private Realm realm;
final Double SIMILARITY_PILLOW = 0.5;
final Double PREDICTION_PILLOW = 3.0;
private APIService client;
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(
GsonConverterFactory.create()
);
Retrofit retrofit =
builder
.client(
httpClient.build()
)
.build();
retrofit2.Call<MovieResponse> call;
#Override
public void onCreate() {
super.onCreate();
instance = this;
Realm.init(this);
RealmConfiguration config = new RealmConfiguration.Builder()
.name("myrealmDB.realm")
.deleteRealmIfMigrationNeeded()
.build();
Realm.setDefaultConfiguration(config);
new Logger.Builder()
.isLoggable(BuildConfig.DEBUG)
.logType(LogType.WARN)
.tag("Iamerror")
.build();
realm = Realm.getDefaultInstance();
MovieRecommendationAlgorithm();
}
public static MovieRecommendationApp getInstance() {
return instance;
}
public static Retrofit getRetrofitInstance() {
return retrofitinstance;
}
public static String getApiKey() {
return API_KEY;
}
public void MovieRecommendationAlgorithm() {
prediction("activeUserId","637",neighbours);
}
public void prediction(String activeUserId, String notYetRatedMovieId,ArrayList<String> neightbours) {
Double activeAVG = avgRating(activeUserId);
Double A = 0.0;
Double B = 0.0;
for (int i = 0; i < neightbours.size(); i++) {
avgRating(neightbours.get(i));
A = A + similarity(activeUserId, neightbours.get(i)) * (getUser_i_MovieRating(neightbours.get(i), notYetRatedMovieId) - avgRating(neightbours.get(i)));
B = B + similarity(activeUserId, neightbours.get(i));
}
final Double prediction = activeAVG + A / B;
if (prediction < PREDICTION_PILLOW) {
return;
}
int movieId = Integer.parseInt(notYetRatedMovieId);
client = retrofit.create(APIService.class);
call = client.getMovieDetails(movieId, MovieRecommendationApp.getApiKey());
call.enqueue(new retrofit2.Callback<MovieResponse>() {
#Override
public void onResponse(retrofit2.Call<MovieResponse> call, retrofit2.Response<MovieResponse> response) {
int statusCode = response.code();
if (response.isSuccessful() == false) {
Logger.w("unsuccessful w status", String.valueOf(statusCode));
} else {
//problem is in this spot
Logger.w( " reponse body is " + response.body().getResults());
}
// Logger.e("Number of movies received: " + movies.size());
}
#Override
public void onFailure(retrofit2.Call<MovieResponse> call, Throwable t) {
}
});
}
}
I double checked the API call using Postman - calling https://api.themoviedb.org/3/movie/637?api_key=*********&language=en-US
got me the desired JSON Body.
Thank you for you time and help.
I don't know if this will be helpfull, but here: if (response.isSuccessful() == false)
It's a quite strange compare a boolean method isSuccessful() with false, the method already return a boolean.
After searching at the movie database api forum , I found this [https://www.themoviedb.org/talk/5667650ec3a36836970002bc][1]
in which it is stated that "The only way we currently support is via query parameters." and there is a big possibility for my problem to be related with the fact that I am using a #Path parameter and not a #Query parameter.
So now the million dollar question is how to convert the
#GET("movie/{id}")
Call<MovieResponse> getMovieDetails(#Path("id") int id, #Query("api_key") String apiKey);
to a Call using the #Query annotation.

java unit test mock HttpClient and webdav

Hello I have a class for doing webdav related operations such as creating a directory, Implementatiion can be seen below (the createDir method). The question is how to test it nicely, perhaps using EasyMock or a similar lib. Any ideas? thanks!
package foobar;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.jackrabbit.webdav.client.methods.DavMethod;
import org.apache.jackrabbit.webdav.client.methods.MkColMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import mypackage.httpdclient.util.URLHandler;
public class WebDavImpl{
private static final String SEPARATOR = " ----- ";
private HttpClient httpClient;
public StorageSpaceClientImpl() {
httpClient = new HttpClient();
}
public String createDir(String dirName) {
String response = null;
String url = URLHandler.getInstance().getDirectoryUrl(dirName);
DavMethod mkcol = new MkColMethod(url);
try {
httpClient.executeMethod(mkcol);
response = mkcol.getStatusCode() + SEPARATOR + mkcol.getStatusText();
} catch (IOException ex) {
} finally {
mkcol.releaseConnection();
}
return response;
}
}

Categories