ResponseCache put never called - java

I am trying to cache images in an android app with this solution Android image caching. I have already implemented a specific ResponseCache and overriden the get and put methods.
Despite that, images are not properly cached. When I debug I can see that the put method of my ResponseCache implementation is never called. My get method is properly called each time a request is made but never is the put method. Nothing is never cached so it can't retrieve any file...
My request use HTTPS so i was wondering if caching the response was allowed or if i'll have to deal with requesting the server every time I want to display my images.
Here is the code :
public class ImageResponseCache extends ResponseCache {
File cacheDir;
public ImageResponseCache(File cacheDir) {
super();
this.cacheDir = cacheDir;
}
#Override
public CacheResponse get(URI uri, String s,
Map<String, List<String>> headers) throws IOException {
final File file = new File(cacheDir, escape(uri.getPath()));
if (file.exists()) {
return new CacheResponse() {
#Override
public Map<String, List<String>> getHeaders()
throws IOException {
return null;
}
#Override
public InputStream getBody() throws IOException {
return new FileInputStream(file);
}
};
} else {
return null;
}
}
#Override
public CacheRequest put(URI uri, URLConnection urlConnection)
throws IOException {
Log.i("Image Response", "PUT");
final File file = new File(cacheDir, escape(urlConnection.getURL()
.getPath()));
return new CacheRequest() {
#Override
public OutputStream getBody() throws IOException {
return new FileOutputStream(file);
}
#Override
public void abort() {
file.delete();
}
};
}
private String escape(String url) {
return url.replace("/", "-").replace(".", "-");
}
}
Here is the function that request my images in an adapter:
private Bitmap requestImage(String file) {
Bitmap bm = null;
Log.d(TAG, "path: " + file);
URL url = null;
HttpURLConnection http = null;
try {
url = new URL(file);
if (url.getProtocol().toLowerCase().equals("https")) {
NetworkUtils.trustAllHosts();
HttpsURLConnection https = (HttpsURLConnection) url
.openConnection();
https.setHostnameVerifier(NetworkUtils.DO_NOT_VERIFY);
http = https;
} else {
http = (HttpURLConnection) url.openConnection();
}
http.setUseCaches(true);
ResponseCache.setDefault(new ImageResponseCache(
ImageAdapter.this.mContext.getCacheDir()));
http.setRequestProperty(
"Authorization",
"Basic "
+ Base64.encodeToString(
(Constants.USER + ":" + Constants.PASSWORD)
.getBytes(), Base64.NO_WRAP));
http.setConnectTimeout(Constants.TIME_OUT);
bm = BitmapFactory.decodeStream((InputStream) http.getContent());
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
}
return bm;
}
Does anyone know what could be wrong?

Related

in Opentelemetry, not able to get parent span

I am new to OpenTelemetry word. I have created spans for my services separately, but when i am try to combine spans of two different services, using context propogation, I am not able to do it successfully.
I have used following code:
// at client side:
public static void sendContext(String resource) {
TextMapSetter<HttpURLConnection> setter =
new TextMapSetter<HttpURLConnection>() {
#Override
public void set(HttpURLConnection carrier, String key, String value) {
carrier.setRequestProperty(key, value);
}
};
HttpURLConnection transportLayer = null;
String urlString = "http://127.0.0.1:8080" + resource;
try {
URL url = new URL(urlString);
transportLayer = (HttpURLConnection) url.openConnection();
} catch (MalformedURLException ex) {
System.out.println(ex.getMessage());
} catch (IOException e) {
System.out.println(e.getMessage());
}
GlobalOpenTelemetry.getPropagators()
.getTextMapPropagator()
.inject(Context.current(), transportLayer, setter);
}
// at server side:
public static Context getContext(HttpServletRequest request) {
TextMapGetter<HttpServletRequest> getter =
new TextMapGetter<HttpServletRequest>() {
#Override
public String get(HttpServletRequest carrier, String key) {
Enumeration<String> headerNames = carrier.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
System.out.println("headerNames.nextElement(): " + headerName);
if (headerName.equals(key)) {
String headerValue = request.getHeader(headerName);
System.out.println("headerValue): " + headerValue);
return headerValue;
}
}
}
return null;
}
#Override
public Iterable<String> keys(HttpServletRequest carrier) {
Set<String> set = new HashSet<String>();
Enumeration<String> headerNames = carrier.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
set.add(headerNames.nextElement());
}
}
return set;
}
};
Context extractedContext =
GlobalOpenTelemetry.getPropagators()
.getTextMapPropagator()
.extract(Context.current(), request, getter);
At server, i am not able to get parent span.
Kindly help on this.
You can refer to OpenTelemetry main documentation from here. It contains the context propagation part but I used HttpHeader type getter as the TextMapGetter with the same functionality which shows in the doc and instead of using
Scope scope = extractedContext.makeCurrent()
as the scope to create a child span, better to use directly without the scope,
tracer.spanBuilder(spanName).setParent(extractedContext)
Because sometimes the automated way to propagate the parent span on the current thread does not work fine.

Pull specific JSON objects from a specific array to put in another activity by an Intent in Android

I am creating a News Feed App, and I want to be able to pull information from a specific listing to a different layout that displays the title, source, image and content of the news listing. On the main page, the JSON will populate the list view with the title, source and image. I've sent an onItemClickListener, and when I click on each entry, I want it to open that entry in the new layout to display all the content. I have a class made just to pull the JSON info, so I'm not sure how to use that in the class with the onItemClick listener. I understand the putExtra, but I'm completely lost on the code to enter to transfer over what I need. Below is code from the page with the list, as well as the JsonQuery class. Thanks for any help!
TopHeadlinesFragment.java
public class TopHeadlinesFragment extends Fragment
implements LoaderManager.LoaderCallbacks<List<News>> {
public static final String NEWS_FEED_URL =
"https://newsapi.org/v2/top-headlines?country=us&apiKey=a3f791903c1a4163b223dd033563084b";
private static final int NEWS_LOADER_ID = 1;
private NewsAdapter mNewsAdapter;
private NewsAdapterListing mNewsAdapterListing;
public TopHeadlinesFragment(){
// Required empty public constructor
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.news_list, container, false);
mNewsAdapter = new NewsAdapter(getActivity(), new ArrayList<News>());
ListView listView = rootView.findViewById(R.id.list);
listView.setAdapter(mNewsAdapter);
final LoaderManager loaderManager = getLoaderManager();
loaderManager.initLoader(NEWS_LOADER_ID, null, this);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mNewsAdapterListing = new NewsAdapterListing(getActivity(), new ArrayList<News>());
News currentNews = mNewsAdapterListing.getItem(position);
Intent newsArticleDisplayIntent = new Intent(getActivity(), FullArticleListing.class);
startActivity(newsArticleDisplayIntent);
}
});
return rootView;
}
#Override
public Loader<List<News>> onCreateLoader(int id, Bundle args) {
return new NewsLoader(getActivity(), NEWS_FEED_URL);
}
#Override
public void onLoadFinished(Loader<List<News>> loader, List<News> data) {
mNewsAdapter.clear();
if (data != null && !data.isEmpty()){
mNewsAdapter.addAll(data);
}
}
#Override
public void onLoaderReset(Loader<List<News>> loader) {
mNewsAdapter.clear();
}
public static class NewsLoader extends AsyncTaskLoader<List<News>> {
private String[] mUrl;
public NewsLoader(Context context, String... url) {
super(context);
mUrl = url;
}
#Override
protected void onStartLoading() {
forceLoad();
}
#Override
public List<News> loadInBackground() {
if (mUrl.length < 1 || mUrl[0] == null) {
return null;
}
return JsonQueryUtils.fetchNewsData(mUrl[0]);
}
}
}
JsonQueryUtils.java
public class JsonQueryUtils {
/** Contains networking and JSON parsing code **/
private static final String LOG_TAG = "JsonQueryUtils";
private JsonQueryUtils(){
}
/** Helper method to fetch news data and call networking code within method **/
public static List<News> fetchNewsData(String requestUrl){
URL url = createUrl(requestUrl);
String jsonResponse = null;
try{
jsonResponse = makeHttpRequest(url);
} catch (IOException e){
Log.e(LOG_TAG, "Error closing input stream", e);
}
List<News> news = extractNews(jsonResponse);
Log.i(LOG_TAG, "fetchNewsData initialized");
return news;
}
private static List<News> extractNews (final String newsJSON) {
if (TextUtils.isEmpty(newsJSON)) {
return null;
}
List<News> news = new ArrayList<>();
try {
JSONObject jsonNewsObject = new JSONObject(newsJSON);
JSONArray newsArray = jsonNewsObject.getJSONArray("articles");
for (int i = 0; i < newsArray.length(); i++) {
JSONObject currentNews = newsArray.getJSONObject(i);
JSONObject source = currentNews.optJSONObject("source");
String imageUrl = currentNews.getString("urlToImage");
Bitmap newsImage = makeHttpRequest(imageUrl);
String title = currentNews.getString("title");
String sourceName = source.getString("name");
String content = currentNews.getString("content");
news.add(new News(newsImage, title, sourceName));
}
} catch (JSONException e) {
e.printStackTrace();
Log.e(LOG_TAG, "problem with parsing", e);
} catch (IOException e){
e.printStackTrace();
}
return news;
}
/**
* Make an HTTP request to the given imageURL and return a Bitmap as the response.
*/
private static Bitmap makeHttpRequest (String imageUrl) throws IOException {
Bitmap newsImage = null;
if (imageUrl == null){
return newsImage;
}
URL url = createUrl(imageUrl);
HttpURLConnection urlConnection = null;
InputStream inputStream = null;
try {
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoInput(true);
urlConnection.connect();
if (urlConnection.getResponseCode() == 200) {
inputStream = urlConnection.getInputStream();
newsImage = BitmapFactory.decodeStream(inputStream);
}
} catch (IOException e) {
Log.e(LOG_TAG, "Error reading bitmap input stream");
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (inputStream != null) {
inputStream.close();
}
}
return newsImage;
}
/**
* Make an HTTP request to the given URL and return a String as the response.
*/
private static String makeHttpRequest(URL url) throws IOException {
String jsonResponse = "";
// If the URL is null, then return early.
if (url == null) {
return jsonResponse;
}
HttpURLConnection urlConnection = null;
InputStream inputStream = null;
try {
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setReadTimeout(10000 /* milliseconds */);
urlConnection.setConnectTimeout(15000 /* milliseconds */);
urlConnection.setRequestMethod("GET");
urlConnection.connect();
// If the request was successful (response code 200),
// then read the input stream and parse the response.
if (urlConnection.getResponseCode() == 200) {
inputStream = urlConnection.getInputStream();
jsonResponse = readFromStream(inputStream);
} else {
Log.e(LOG_TAG, "Error response code: " + urlConnection.getResponseCode());
}
} catch (IOException e) {
Log.e(LOG_TAG, "Problem reading input stream.", e);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (inputStream != null) {
inputStream.close();
}
}
return jsonResponse;
}
/**
* Convert the {#link InputStream} into a String which contains the
* whole JSON response from the server.
*/
private static String readFromStream(InputStream inputStream) throws IOException {
StringBuilder output = new StringBuilder();
if (inputStream != null) {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
BufferedReader reader = new BufferedReader(inputStreamReader);
String line = reader.readLine();
while (line != null) {
output.append(line);
line = reader.readLine();
}
}
return output.toString();
}
/** Helper method to create {#link} URL object **/
private static final URL createUrl(String stringUrl) {
URL url = null;
try {
url = new URL(stringUrl);
} catch (MalformedURLException e) {
Log.e(LOG_TAG, "createUrl: error", e);
}
return url;
}
}
I noticed you extracted the 'content' from JSON response but I don't see anywhere the variable 'content' getting used to construct the News object... Is there a reason why you don't include it to News object?
Regarding sending the News object to the next activity, there are few ways to achieve this.
Use Parcelable to send the News to your next activity/fragment. For more details, click here.
Install GSON library and simple convert your News object to Json String. Put that String in your Intent as an extra and launch the next Activity. Retrieve the data by calling new Gson().fromJson(). However, since your object has Bitmap field, this won't be a suitable approach. For more details, click here
This is what I would have done, if the API allows: Simply call the API request again for more details about the current feed. For example, you can execute another API request in your FullArticleActivity along with an ID that is associated with the selected feed. (i.e. User clicks a feed with an id #3 -> Pass the id(Integer) to the next Activity as an extra -> Retrieve the id from extras and make another API request using the id to retrieve full article details.) However, this is possible only when your API provides a GET method like this.
Create a Singleton and let it hold your object temporarily. Retrieve the object in the next activity by simple calling something like YourSingletonClass.getInstance().getNews().

SignatureDoesNotMatch error when deleting multiple objects from S3 bucket

I m adding code to delete multiple objects from S3. POST request to delete returns 403 status. I am adding this code in legacy code and unfortunately cannot change to change AWS S3 library. Not able to figure out if I am missing a header or if the logic is incorrect.
public Response deleteMultipleObjects(Delete object) throws MalformedURLException, IOException, StorageException {
HttpURLConnection request = null;
try(ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(out)) {
os.writeObject(object);
Calendar now = Calendar.getInstance();
Map<String, List<String>> headers = new HashMap<>();
headers.put(AWSAuthConnection.CONTENT_TYPE_HEADER, Arrays.asList("application/octet-stream"));
headers.put(AWSAuthConnection.CONTENT_LENGTH_HEADER, Arrays.asList(Integer.toString(out.toByteArray().length)));
headers.put(AWSAuthConnection.AMAZON_DATE_HEADER, Arrays.asList(convertDateToString(now, AWSAuthConnection.TIMESTAMP_FORMAT, AWSAuthConnection.TIME_ZONE_UTC)));
headers.put(AWSAuthConnection.AMAZON_CONTENT_SHA256_HEADER, Arrays.asList(buildHash(out.toByteArray(), SHA256_HASH, EncodingType.HEX)));
headers.put(AWSAuthConnection.CONTENT_MD5_HEADER, Arrays.asList(buildHash(out.toByteArray(), AWSAuthConnection.MD5_HASH, AWSAuthConnection.EncodingType.BASE64)));
request = makeRequest("POST", bucket+"/?delete", headers, null);
request.setDoOutput(true);
request.getOutputStream().write(object == null ? new byte[]{} : out.toByteArray());
return new Response(request);
}
}
private String buildHash(final byte[] contentToHash, final String hashMethod, final AWSAuthConnection.EncodingType encodingType) throws StorageException{
try {
MessageDigest digest = MessageDigest.getInstance(hashMethod);
byte[] contentHash = digest.digest(contentToHash);
if (encodingType == AWSAuthConnection.EncodingType.HEX) {
return Hex.encodeHexString(contentHash);
} else {
return Base64.encodeBase64String(contentHash);
}
} catch (NoSuchAlgorithmException e) {
throw new StorageException(StorageException.ERROR_INVALID_STORAGE_TYPE, e);
}
}
private HttpURLConnection makeRequest(String method, String resource, Map<String, List<String>> headers, StorageObject object) throws MalformedURLException, IOException {
URL url = makeURL(resource);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod(method);
connection.setUseCaches(true);
addHeaders(connection, headers);
if (object != null) addMetadataHeaders(connection, object.metadata);
addAuthHeader(connection, method, resource);
return connection;
}
private void addAuthHeader(HttpURLConnection connection, String method, String resource) {
String canonicalString =
Utils.makeCanonicalString(method, resource, connection.getRequestProperties());
String encodedCanonical = Utils.encode(this.info, canonicalString, false);
connection.setRequestProperty("Authorization", "AWS " + this.info + ":" + encodedCanonical);
}
Error from S3:
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>.......</Error>
Has anyone faced this issue before? If you know a way to fix, please help

Printing issue with internet download manager

I want to print a document in my java web application using servlet and i clear report info to avoid download resume(SecurityContext.cleanReportInfo()).
everything is ok when you don't have IDM in your system but when IDM is running it sends 2 request instead 1 and everything goes wrong by redirecting to /403 like the code below .
PrintReportServlet
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ReportDto reportInfo = SecurityContext.getReportInfo();
if (reportInfo != null) {
ServletOutputStream outputStream = response.getOutputStream();
try {
generateHeaders(response, reportInfo);
generateContents(outputStream, reportInfo);
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Error occurred during print report, nested error message: {0}", e.getMessage());
} finally {
outputStream.flush();
outputStream.close();
SecurityContext.cleanReportInfo();
}
} else {
response.sendRedirect(request.getContextPath() + "/403");
}
}
SecurityContext.java
public static void cleanReportInfo() {
SecurityContext.getCurrentSession().setAttribute("Report_Info", null);
}
errorreportController.js
$scope.printErrorList = function () {
errorReportService.printErrorList(function () {
window.open(contextPath + "/PrintReport");
});
};
ErrorReportController.java
#RequestMapping(value = "/printError", method = RequestMethod.GET)
#ResponseBody
public String printError() {
ReportDto reportDto = errorReportService.getReportInfo();
SecurityContext.setReportInfo(reportDto);
return success();
}
ErrorReportServiceImpl
public ReportDto getReportInfo() {
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put("jalaliDate", DateUtil.convertToJalali(new Date()).toStringBySlash());
parameters.put("alahImagePath", ReportUtil.getImagesPath() + File.separator + "alah.png");
parameters.put("sepahImagePath", ReportUtil.getImagesPath() + File.separator + "sepah.png");
parameters.put("reporter", SecurityContext.getCurrentUserName());
parameters.put("classify", "Normal");
parameters.put("userId",SecurityContext.getCurrentUserId());
ReportDto reportDto = new ReportDto(
ReportNames.ErrorReport, DataItems.Report_Type_PDF,
"error",
parameters);
return reportDto;
}

How to do an HTTP Post in Android to web api

I am trying to do a post to web api from android. The below is the code that I am using in android. The code is running without exception however the data is not inserted to the database. I included the code that I am using.
#Override
protected List doInBackground(Void... params)
{
List userDetails3 = new ArrayList();
URL url = null;
String urlshared = "http://10.0.0.9/MyWebApi/api/Student/PostAddStudent?userName="+"s4"+"&"+"password="+"1234"+"&"+"firsName="+"z"+"&"+"lastName="+"g"+"&"+"telephone="+"9160000000"+"&"+"address="+"2300 xxx"+"&"+"aliasMailId="+"s1.xx"+"&"+"emailId="+"xx#gmail.com"+"&"+"skypeId="+"z.g"+"";
try {
url = new URL(urlshared);
}
catch (MalformedURLException exception)
{
exception.printStackTrace();
}
HttpURLConnection httpURLConnection = null;
DataOutputStream dataOutputStream = null;
try
{
httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
httpURLConnection.setRequestMethod("POST");
PrintWriter out = new PrintWriter(httpURLConnection.getOutputStream()); // this code is executed without exception
}
catch (IOException exception)
{
exception.printStackTrace();
}
return userDetails3; // (in debug) the code will run successfuly till here without exception
}
I am trying to access the PostAddStudent in the webapi. The below is my implementation of the controller and I excluded the codes inside the methods. For your information, I did test "PostAddStudent" and the other methods in the RegisterController by using the postman and they are working fine and the data inserted to database.
public class RegisterController : ApiController
{
public IEnumerable<Register> GetRegisterAuth(string userName,string password)
{
//return instance of register
}
public IEnumerable<Register> GetRegisterByUserName(string userName)
{
//return instance of register
}
public HttpResponseMessage PostAddInstructor(string instUserName, string instPassword, string instFirsName, string instLastName, string instTelephone, string instAddress, string instAliasMailId, string instEmailId, string instSkypeId)
{
//add to database and if okay will return System.Net.HttpStatusCode.Created
var response = Request.CreateResponse<Instructor>(System.Net.HttpStatusCode.Created, inst);
//if error exist then just return Badrequest
var response = Request.CreateResponse<Instructor>(System.Net.HttpStatusCode.BadRequest, inst);
}
public HttpResponseMessage PostAddStudent(string userName, string password, string firsName, string lastName, string telephone, string address, string aliasMailId, string emailId, string skypeId)
{
//add to database and if okay will return System.Net.HttpStatusCode.Created
var response = Request.CreateResponse<Instructor>(System.Net.HttpStatusCode.Created, inst);
//if error exist then just return Badrequest
var response = Request.CreateResponse<Instructor>(System.Net.HttpStatusCode.BadRequest, inst);
}
}
the below is the RouteConfig
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
//config.EnableSystemDiagnosticsTracing();
}
}
the below is the WebApiConfig
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
I need the android code that can do the post to PostAddStudent.
thanks

Categories