How to get random access to a file on SD-Card by means of API presented for Lollipop? - android-5.0-lollipop

My application uses Java class RandomAccessFile to read/write bytes to a file on SD card randomly by means of realization of SeekableByteChannel interface. Now I need rewrite it for Android 5.0 with new Lollipop API.
I have found the only way to read:
InputStream inputStream = getContentResolver().openInputStream(uri);
and write:
ParcelFileDescriptor pfd = getActivity().getContentResolver().openFileDescriptor(uri, "w");
FileOutputStream fileOutputStream = new FileOutputStream(pfd.getFileDescriptor());
from/to a file in new API.
I would like to have an ability to set channel in some random position and read/write bytes to that position. Is it possible to do that in new SDK 21? Does new SDK imply this way obtaining of channels:
FieInputChannel fieInputChannel = fileInputStream.getChannel();
FieOutputChannel fieOutputChannel = fileOutputStream.getChannel();
or some other approach?

It seems the only way to get a random read/write access to a file on SD card for SDK 21 (Lollipop) is as follows:
import android.content.Context;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import com.jetico.bestcrypt.FileManagerApplication;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class SecondaryCardChannel {//By analogy with the java.nio.channels.SeekableByteChannel
private FileChannel fileChannel;
private ParcelFileDescriptor pfd;
private boolean isInputChannel;
private long position;
public SecondaryCardChannel(Uri treeUri, Context context) {
try {
pfd = context.getContentResolver().openFileDescriptor(treeUri, "rw");
FileInputStream fis = new FileInputStream(pfd.getFileDescriptor());
fileChannel = fis.getChannel();
isInputChannel = true;
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public int read(ByteBuffer buffer) {
if (!isInputChannel) {
try {
fileChannel.close();
FileInputStream fis = new FileInputStream(pfd.getFileDescriptor());
fileChannel = fis.getChannel();
isInputChannel = true;
} catch (IOException e) {
e.printStackTrace();
}
}
try {
fileChannel.position(position);
int bytesRead = fileChannel.read(buffer);
position = fileChannel.position();
return bytesRead;
} catch (IOException e) {
e.printStackTrace();
return -1;
}
}
public int write(ByteBuffer buffer) {
if (isInputChannel) {
try {
fileChannel.close();
FileOutputStream fos = new FileOutputStream(pfd.getFileDescriptor());
fileChannel = fos.getChannel();
isInputChannel = false;
} catch (IOException e) {
e.printStackTrace();
}
}
try {
fileChannel.position(position);
int bytesWrite = fileChannel.write(buffer);
position = fileChannel.position();
return bytesWrite;
} catch (IOException e) {
e.printStackTrace();
return -1;
}
}
public long position() throws IOException {
return position;
}
public SecondaryCardChannel position(long newPosition) throws IOException {
position = newPosition;
return this;
}
public long size() throws IOException {
return fileChannel.size();
}
public SecondaryCardChannel truncate(long size) throws IOException {
fileChannel.truncate(size);
return this;
}
}
EDIT 15/03/2017:
Little bit optimized version looks like
import android.content.Context;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class SecondaryCardChannel {
private ParcelFileDescriptor pfdInput, pfdOutput;
private FileInputStream fis;
private FileOutputStream fos;
private long position;
public SecondaryCardChannel(Uri treeUri, Context context) {
try {
pfdInput = context.getContentResolver().openFileDescriptor(treeUri, "r");
pfdOutput = context.getContentResolver().openFileDescriptor(treeUri, "rw");
fis = new FileInputStream(pfdInput.getFileDescriptor());
fos = new FileOutputStream(pfdOutput.getFileDescriptor());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public int read(ByteBuffer buffer) {
try {
FileChannel fch = fis.getChannel();
fch.position(position);
int bytesRead = fch.read(buffer);
position = fch.position();
return bytesRead;
} catch (IOException e) {
e.printStackTrace();
return -1;
}
}
public int write(ByteBuffer buffer) {
try {
FileChannel fch = fos.getChannel();
fch.position(position);
int bytesWrite = fch.write(buffer);
position = fch.position();
return bytesWrite;
} catch (IOException e) {
e.printStackTrace();
return -1;
}
}
public long position() throws IOException {
return position;
}
public SecondaryCardChannel position(long newPosition) throws IOException {
position = newPosition;
return this;
}
public long size() throws IOException {
return fis.getChannel().size();
}
public void force(boolean metadata) throws IOException {
fos.getChannel().force(metadata);
pfdOutput.getFileDescriptor().sync();
}
public long truncate(long size) throws Exception {
FileChannel fch = fos.getChannel();
try {
fch.truncate(size);
return fch.size();
} catch (Exception e){ // Attention! Truncate is broken on removable SD card of Android 5.0
e.printStackTrace();
return -1;
}
}
public void close() throws IOException {
FileChannel fch = fos.getChannel();
fch.close();
fos.close();
fis.close();
pfdInput.close();
pfdOutput.close();
}
}

Related

The path to a database with jee maven project

I'm currently making a website with Java EE, using maven, thymeleaf, and hosting it on heroku (database addon is JawsDBMySQL).
I've created a simple html page in order to check the good working of it.
Of course it works perfectly for a local upload : the file goes to a folder I've designed.
In my data base the path to my local storage is stored as a string.
I've also add a longblob column, but I did not really understood how to use it.
Now I want to store files into my database when my application is online.
I didn't found solution that perfectly match with my issue, but I'm quite sure it is pretty simple.
Hoping I have been clear enough,
thanks for your help.
Servlet that display a page on /home2 with the list of the pictures
package marquise.servlets;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import marquise.services.InformationLibrary;
#WebServlet("/home2")
public class HomeServlet extends AbstractGenericServlet2 {
private static final long serialVersionUID = 5402133218271984030L;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
TemplateEngine templateEngine = this.createTemplateEngine(req);
WebContext context = new WebContext(req, resp, getServletContext());
//Country countryFilter = (Country) req.getSession().getAttribute("countryFilter");
context.setVariable("images", InformationLibrary.getInstance().listAllImages());
//context.setVariable("cities", CityService.getInstance().listAllCities(countryFilter));
//context.setVariable("countries", Country.values());
//context.setVariable("countryFilterSelected", countryFilter);
templateEngine.process("home", context, resp.getWriter());
}
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String countryString = req.getParameter("countryFilter");
resp.sendRedirect("home2");
}
}
Servlet for the path
#WebServlet("/imagepicture")
public class CityPictureServlet extends AbstractGenericServlet2 {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Integer imageId = Integer.parseInt(req.getParameter("id"));
Path picturePath = InformationLibrary.getInstance().getPicturePatch(imageId);
Files.copy(picturePath, resp.getOutputStream());
}
}
servlet that print image details (not important right now)
package marquise.servlets;
#WebServlet("/detail")
public class CityDetailServlet extends AbstractGenericServlet2 {
private static final long serialVersionUID = 8559083626521311046L;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
TemplateEngine templateEngine = this.createTemplateEngine(req);
WebContext context = new WebContext(req, resp, getServletContext());
Integer idImage = Integer.parseInt(req.getParameter("id"));
context.setVariable("image", InformationLibrary.getInstance().getImage(idImage));
//context.setVariable("comments", InformationLibrary.getInstance().listCommentsByCity(idCity));
context.setVariable("comments", InformationLibrary.getInstance().listAllImages());
templateEngine.process("imagedetail", context, resp.getWriter());
}
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Integer cityId = Integer.parseInt(req.getParameter("id"));
resp.sendRedirect(String.format("detail?id=%d", cityId));
resp.sendRedirect("home2");
}
}
HTML page displaying the list of my images
<!doctype html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<title>City Explorer</title>
<link rel="stylesheet" href="bootstrap/bootstrap.min.css">
<link rel="stylesheet" href="fontawesome/css/font-awesome.min.css">
<link rel="stylesheet" href="css/custom.css">
</head>
<body>
<header th:replace="~{common::header}"></header>
<div id="mainContent" class="container-fluid">
<section class="cityfilters">
<h3>Filters</h3>
<form class="form-inline" method="post">
<div class="form-group">
<label for="countryInput">Country</label>
<select class="form-control" id="countryInput" name="countryFilter">
<option value="">All countries</option>
<option th:each="country : ${countries}" th:value="${country}" th:selected="${countryFilterSelected} == ${country}">[[${country.label}]]</option>
</select>
</div>
<input type="submit" class="btn btn-default" value="Filter">
</form>
</section>
<section class="citylist">
<article class="citybox" th:each="image : ${images}">
<h3>
[[${image.name}]]
<a th:href="'deleteimage?id='+${image.id}" class="btn btn-xs btn-danger pull-right">
<i class="fa fa-times" aria-hidden="true"></i>
</a>
</h3>
<p th:text="${image.summary}" class="summary"></p>
<div class="btn-toolbar actionbar" role="toolbar">
<div class="btn-group" role="group">
<a th:href="'detail?id='+${image.id}" class="btn btn-primary"><i
class="fa fa-eye" aria-hidden="true"></i> See details</a>
</div>
</div>
<aside class="cityPhoto">
<img th:src="'imagepicture?id='+${image.id}" th:alt="'Vignette '+${image.name}">
</aside>
</article>
</section>
</div>
</body>
</html>
My Library Class with the path to my computer
public class InformationLibrary {
private static class InformationLibraryHolder{
private final static InformationLibrary instance = new InformationLibrary();
}
public static InformationLibrary getInstance(){
return InformationLibraryHolder.instance;
}
private InformationDao informationDao = new InformationDaoImpl();
private UtilisateurDao utilisateurDao = new UtilisateurDaoImpl();
private CommentaireDao commentaireDao = new CommentaireDaoImpl();
private ArticleDao articleDao = new ArticleDaoImpl();
private IdentifiantDao identifiantDao = new IdentifiantDaoImpl();
private ImageDao imageDao = new ImageDao();
private static final String PICTURE_MAIN_DIRECTORY = "/Users/louiscauvray/git/projet/src/main/resources";
private ElementsSiteDao elementsSiteDao = new ElementsSiteDao();
private InformationLibrary() {
}
//Recuperer les informations sur les utilisateurs
public List<Information> listFilms() {
return informationDao.listInformations();
}
public Information getInformation(Integer id) {
return informationDao.getInformation(id);
}
public Information addInformation(Information information) {
return informationDao.addInformation(information);
}
public List<Utilisateur> listUtilisateurs() {
return utilisateurDao.listUtilisateurs();
}
public Utilisateur getUtilisateur(Integer id) {
return utilisateurDao.getUtilisateur(id);
}
public Utilisateur getUtilisateurByNom(String nom){
return utilisateurDao.getUtilisateurByNom(nom);
}
public Utilisateur addUtilisateur(String nom, String prenom) {
return utilisateurDao.addUtilisateur(nom, prenom);
}
//Gerer les commentaires visible en backoffice
public List<Commentaire> listCommentaires(){
return commentaireDao.listCommentaires();
}
public Commentaire addCommentaire(String email ,String commentaire){
return commentaireDao.addCommentaire(email, commentaire);
}
public List<Article> listArticles(){
return articleDao.listArticles();
}
public Article addArticle(String title, String texte, LocalDate datePublication, String auteur) {
return articleDao.addArticle(title, texte, datePublication, auteur);
}
public Identifiant getIdentifiant(String login, String motDePasse){
return identifiantDao.getIdentifiant(login, motDePasse);
}
//Methode pour appeler les image et les chemins des images
public List<Image> listAllImages() {
return imageDao.listImages();
}
public Image getImage(Integer id) {
if(id == null) {
throw new IllegalArgumentException("Image id must be provided.");
}
return imageDao.getImage(id);
}
public void addImage(Image newImage, Part picture) throws IOException {
if(newImage == null){
throw new IllegalArgumentException("An image must be provided.");
}
if(newImage.getName() == null || "".equals(newImage.getName())) {
throw new IllegalArgumentException("An image must have a name.");
}
if(newImage.getSummary() == null || "".equals(newImage.getSummary())) {
throw new IllegalArgumentException("An image must have a summary.");
}
if(picture == null){
throw new IllegalArgumentException("An image must contain a picture.");
}
Path picturePath = Paths.get(PICTURE_MAIN_DIRECTORY, picture.getSubmittedFileName());
imageDao.addImage(newImage, picturePath.toString());
Files.copy(picture.getInputStream(), picturePath);
}
public Path getPicturePatch(Integer imageId) {
String picturePathString = imageDao.getPicturePath(imageId);
if(picturePathString == null) {
return getDefaultPicturePath();
} else {
Path picturePath = Paths.get(imageDao.getPicturePath(imageId));
if(Files.exists(picturePath)) {
return picturePath;
} else {
return getDefaultPicturePath();
}
}
}
private Path getDefaultPicturePath() {
try {
return Paths.get(this.getClass().getClassLoader().getResource("city-no-photo.png").toURI());
} catch (URISyntaxException e) {
return null;
}
}
// ElementsSite Dao
public void modifierElementTexte(String idElement, String contenuElement) {
elementsSiteDao.modifierElementTexte(idElement, contenuElement);
}
public void modifierElementImage(String idElement, String contenuElement, String cheminElement) {
elementsSiteDao.modifierElementImage(idElement, contenuElement, cheminElement);
}
public ElementsSite getElementById(String id) {
return elementsSiteDao.getElementById(id) ;
}
}
My Dao Class where methods to display images are defined
import marquise.daos.impl.DataSourceProvider;
import marquise.exceptions.CityExplorerRuntimeException;
import marquise.projos.Image;
public class ImageDao {
public List<Image> listImages() {
List<Image> images = new ArrayList<Image>();
try (Connection connection = DataSourceProvider.getInstance().getDataSource().getConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM image ORDER BY name")) {
while (resultSet.next()) {
images.add(
new Image(resultSet.getInt("id"), resultSet.getString("name"), resultSet.getString("summary")));
}
} catch (SQLException e) {
throw new CityExplorerRuntimeException("Error when getting images", e);
}
return images;
}
public Image getImage(Integer id) {
try (Connection connection = DataSourceProvider.getInstance().getDataSource().getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT * FROM image WHERE id = ?")) {
statement.setInt(1, id);
try (ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
return new Image(resultSet.getInt("id"), resultSet.getString("name"), resultSet.getString("summary"));
}
}
} catch (SQLException e) {
throw new CityExplorerRuntimeException("Error when getting images", e);
}
return null;
}
public void addImage(Image newImage, String picturePath) {
try (Connection connection = DataSourceProvider.getInstance().getDataSource().getConnection();
PreparedStatement statement = connection.prepareStatement("INSERT INTO image(name, summary, picture) VALUES (?, ?, ?)")) {
statement.setString(1, newImage.getName());
statement.setString(2, newImage.getSummary());
statement.setString(3, picturePath);
statement.executeUpdate();
} catch (SQLException e) {
throw new CityExplorerRuntimeException("Error when getting images", e);
}
}
public String getPicturePath(Integer id) {
try (Connection connection = DataSourceProvider.getInstance().getDataSource().getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT picture FROM image WHERE id = ?")) {
statement.setInt(1, id);
try (ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
return resultSet.getString("picture");
}
}
} catch (SQLException e) {
throw new CityExplorerRuntimeException("Error when getting images", e);
}
return null;
}
}
Finally I found a solution to my problem :
I added a longblob column into my data base table, and changed a bit my method.
Here is my final code if you need it :
The DaoClass :
package marquise.daos;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import marquise.daos.impl.DataSourceProvider;
import marquise.exceptions.CityExplorerRuntimeException;
import marquise.projos.Image;
public class ImageDao {
public List<Image> listImages() {
List<Image> images = new ArrayList<Image>();
try (Connection connection = DataSourceProvider.getInstance().getDataSource().getConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM image ORDER BY name")) {
while (resultSet.next()) {
images.add(
new Image(resultSet.getInt("id"), resultSet.getString("name"), resultSet.getString("summary")));
}
} catch (SQLException e) {
throw new CityExplorerRuntimeException("Error when getting images", e);
}
return images;
}
public Image getImage(Integer id) {
try (Connection connection = DataSourceProvider.getInstance().getDataSource().getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT * FROM image WHERE id = ?")) {
statement.setInt(1, id);
try (ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
return new Image(resultSet.getInt("id"), resultSet.getString("name"), resultSet.getString("summary"));
}
}
} catch (SQLException e) {
throw new CityExplorerRuntimeException("Error when getting images", e);
}
return null;
}
public void addImage(Image newImage, String picturePath) {
try (Connection connection = DataSourceProvider.getInstance().getDataSource().getConnection();
PreparedStatement statement = connection.prepareStatement("INSERT INTO image(name, summary, picture) VALUES (?, ?, ?)")) {
statement.setString(1, newImage.getName());
statement.setString(2, newImage.getSummary());
statement.setString(3, picturePath);
statement.executeUpdate();
} catch (SQLException e) {
throw new CityExplorerRuntimeException("Error when getting images", e);
}
}
public void addImage(Image img, InputStream is){
try(Connection connection = DataSourceProvider.getInstance().getDataSource().getConnection();
PreparedStatement statement = connection.prepareStatement("INSERT INTO image(name, summary, image) VALUES (?, ?, ?)")) {
statement.setString(1, img.getName());
statement.setString(2, img.getSummary());
statement.setBinaryStream(3, is);
statement.executeUpdate();
} catch (SQLException e) {
throw new CityExplorerRuntimeException("Error when getting images", e);
}
}
public String getPicturePath(Integer id) {
try (Connection connection = DataSourceProvider.getInstance().getDataSource().getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT picture FROM image WHERE id = ?")) {
statement.setInt(1, id);
try (ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
return resultSet.getString("picture");
}
}
} catch (SQLException e) {
throw new CityExplorerRuntimeException("Error when getting images", e);
}
return null;
}
public InputStream getPicture(Integer id) {
try (Connection connection = DataSourceProvider.getInstance().getDataSource().getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT image FROM image WHERE id = ?")) {
statement.setInt(1, id);
try (ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
return resultSet.getBinaryStream("image");
}
}
} catch (SQLException e) {
throw new CityExplorerRuntimeException("Error when getting images", e);
}
return null;
}
/*public InputStream getPicture(Integer id) {
try (Connection connection = DataSourceProvider.getInstance().getDataSource().getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT image FROM image WHERE id = ?")) {
statement.setInt(1, id);
try (ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
return resultSet.getBlob("image") == null ? null : resultSet.getBlob("image").getBinaryStream();
}
}
} catch (SQLException e) {
throw new CityExplorerRuntimeException("Error when getting images", e);
}
return null;
}*/
}
the addimage servlet :
package marquise.servlets;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import marquise.projos.Image;
import marquise.services.InformationLibrary;
#WebServlet("/addimage")
#MultipartConfig
public class ImageAddServlet extends AbstractGenericServlet2 {
private static final long serialVersionUID = -3497793006266174453L;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("UTF-8");
TemplateEngine templateEngine = this.createTemplateEngine(req);
WebContext context = new WebContext(req, resp, getServletContext());
if(req.getSession().getAttribute("imageCreationError") != null) {
context.setVariable("errorMessage", req.getSession().getAttribute("imageCreationError"));
context.setVariable("image", (Image) req.getSession().getAttribute("imageCreationData"));
req.getSession().removeAttribute("imageCreationError");
req.getSession().removeAttribute("imageCreationData");
} else {
context.setVariable("image", new Image(null, null, null));
}
context.setVariable("countries", context);
templateEngine.process("connectedUsers/imageadd", context, resp.getWriter());
}
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
String summary = req.getParameter("summary");
Part imagePicture = req.getPart("picture");
Image newImage = new Image(null, name, summary);
InputStream is = imagePicture.getInputStream();
try {
InformationLibrary.getInstance().addImage(newImage, is);
resp.sendRedirect("certificatsAdmin");
} catch (IllegalArgumentException|IOException e) {
req.getSession().setAttribute("imageCreationError", e.getMessage());
req.getSession().setAttribute("imageCreationData", newImage);
resp.sendRedirect("addimage");
}
}
}
The listImage servlet :
package marquise.servlets;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import marquise.services.InformationLibrary;
#WebServlet("/certificatsAdmin")
public class listeCertifServlet extends AbstractGenericServlet2 {
private static final long serialVersionUID = 5402133218271984030L;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("UTF-8");
PrintWriter out = resp.getWriter();
HttpSession session=req.getSession(false);
if(session != null){}
else{
resp.sendRedirect("connexion");
out.println("Veuillez entre un mot de passe correct");
}
TemplateEngine templateEngine = this.createTemplateEngine(req);
WebContext context = new WebContext(req, resp, getServletContext());
//Country countryFilter = (Country) req.getSession().getAttribute("countryFilter");
context.setVariable("images", InformationLibrary.getInstance().listAllImages());
//context.setVariable("cities", CityService.getInstance().listAllCities(countryFilter));
//context.setVariable("countries", Country.values());
//context.setVariable("countryFilterSelected", countryFilter);
templateEngine.process("admin/certificatsAdmin", context, resp.getWriter());
}
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String countryString = req.getParameter("countryFilter");
resp.sendRedirect("certificatsAdmin");
}
}

i unable to convert JSObject of API key

i am using the APi of https://openweathermap.org/current
i want to get particular weather part from the API as below my code so i am using JSON
Here below link is API key where i want weather part
http://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b1b15e88fa797225412429c1c50c122a1
Value null of type org.json.JSONObject$1 cannot be converted to JSONObject
I am using the AsyncTask
My MainActivity is here
public class MainActivity extends AppCompatActivity {
String data ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DownloadWeatherData downloadWeatherData = new DownloadWeatherData();
try {
downloadWeatherData.execute("http://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b1b15e88fa797225412429c1c50c122a1").get();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Here is my java file
public class DownloadWeatherData extends AsyncTask {
String weatherdata;
#Override
protected String doInBackground(String... urls)
{
try {
URL url = new URL(urls[0]);
HttpURLConnection connection =(HttpURLConnection) url.openConnection();
connection.connect();
InputStreamReader inputStreamReader = new InputStreamReader(connection.getInputStream());
int data = inputStreamReader.read();
while(data!=-1)
{
char str = (char)data;
weatherdata+=str;
data = inputStreamReader.read();
}
return weatherdata;
}
catch (MalformedURLException e)
{
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String s)
{
super.onPostExecute(s);
try {
JSONObject jsonObject = new JSONObject(s);
String info = jsonObject.getString("weather");
Log.d("weatherpart",info);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
You are doing it wrong. Weather is an array not a json object. Do it like this:
JSONObject jsonObj = new JSONObject(s);
JSONArray ja_data = jsonObj.getJSONArray("weather");
int length = ja_data.length();
for(int i=0; i<length; i++) {
JSONObject jsonObj = ja_data.getJSONObject(i);
.
.
.
}

Display JSON Objects data in Android AutoCompleteTextview

public class MainActivity extends AppCompatActivity {
private AutoCompleteTextView autoCompleteTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
autoCompleteTextView = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView);
new HttpGetTask().execute("http://192.168.0.107/abc/translator.php");
}
public class HttpGetTask extends AsyncTask<String, String, List<TranslatorModel>> {
#Override
protected List<TranslatorModel> doInBackground(String... params) {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
URL url = new URL(params[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
String finalJson = buffer.toString();
JSONArray parentArray = new JSONArray(finalJson);
List<TranslatorModel> translatorModelList = new ArrayList<>();
for(int i= 0; i<parentArray.length();i++) {
JSONObject finalObject = parentArray.getJSONObject(i);
TranslatorModel translatorModel = new TranslatorModel();
translatorModel.setEnglish(finalObject.getString("englishSentence"));
translatorModelList.add(translatorModel);
}
return translatorModelList;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onPostExecute(List<TranslatorModel> data) {
super.onPostExecute(data);
}
}
}
englishSentence is a string json object . setter and getter methods are defined in a TranslatorModel class. i want to display englishSentence values in my autocompleteTextView
Problem:
Which code will be used for displaying data in autocompletetextview ?
Where to add array adaptar class and which code will work ?
Which code will be used onPostExecute Method ?
add ArrayAdapter inside onPostExecute method
#Override
protected void onPostExecute(List<TranslatorModel> data) {
ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this,android.R.layout.simple_list_item_1,data);
autoCompleteTextView.setAdapter(adapter);
autoCompleteTextView.setThreshold(1);
super.onPostExecute(data);
}

Error in deleting file using Drive Rest API + Drive Android Api. drive.files().delete(driveid.getResourceId())

Drive REST API + GDAA not able to delete the file.
Gone through this question and comments How to delete a file on google drive using Google Drive Android API but when I use driveid.getResourceId(); to pass as a fileId parameter to old Drive API service.files().delete() method its giving error:
Error Required parameteres must be passed it may lead to Dead Lock
My code:
public class MainActivity extends Activity implements ConnectionCallbacks,
OnConnectionFailedListener {
private GoogleAccountCredential credential;
private static final int REQUEST_CODE_CREATOR = 2;
private static final int REQUEST_CODE_RESOLUTION = 3;
private static final int PICKFILE_RESULT_CODE = 1;
private static Uri fileUri;
private ContentsResult contentsresult;
private GoogleApiClient mGoogleApiClient;
byte[] buffer;
String EXISTING_FILE_ID = "";
int folderCreated = 0;
SharedPreferences prefs;
ArrayList<String> dbfileid = new ArrayList<String>();
ArrayList<String> dbfilename = new ArrayList<String>();
String fdd="";
DriveFolderResult sky;
private DriveId mFolderDriveId;
String isfolder;
SharedPreferences sp;
String Shared="Shared";
String folderid="";
SQLiteOpenHelper dbhelper;
SQLiteDatabase database;
int j=0;
String songfileid="";
private static com.google.api.services.drive.Drive service;
private static final String LOGTAG="EXPLORECA";
private static final String DATABASE_NAME="file.db";
private static final int DATABASE_VERSION=1;
private static final String TABLE="fileids";
private static final String filename="fname";
private static final String fileid="fid";
String realid ="";
#Override
protected void onResume() {
super.onResume();
initDrive();
}
private void initDrive() {
credential = GoogleAccountCredential.usingOAuth2(this,Arrays.asList(DriveScopes.DRIVE.split(",")));
credential.setSelectedAccountName("shivrajp130#gmail.com");
service = getDriveService(credential);
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(this).addApi(com.google.android.gms.drive.Drive.API)
.addScope(com.google.android.gms.drive.Drive.SCOPE_FILE).setAccountName("shivrajp130#gmail.com")
.addConnectionCallbacks(this).addOnConnectionFailedListener(this).build();
}
mGoogleApiClient.connect();
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Called whenever the API client fails to connect.
if (!result.hasResolution()) {
// show the localized error dialog.
showToast("Error in on connection failed");
GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(), this,
0).show();
return;
}
try {
result.startResolutionForResult(this, REQUEST_CODE_RESOLUTION);
} catch (SendIntentException e) {
showToast("error" + e.toString());
}
}
#Override
public void onConnected(Bundle connectionHint) {
showToast("Inside Connected");
sp = getSharedPreferences(Shared, Context.MODE_PRIVATE);
showToast("Inside Connected");
createSkyFolder();
}
private void createSkyFolder()
{
// TODO Auto-generated method stub
try
{
showToast("creating Folder");
if(!sp.getString(isfolder, "false").contains("created"))
{
MetadataChangeSet changeSet = new MetadataChangeSet.Builder().
setTitle("Sky folder").build();
sky = Drive.DriveApi.getRootFolder(getGoogleApiClient())
.createFolder(getGoogleApiClient(), changeSet).await();
showToast("folder created");
sp.edit().putString(isfolder, "created").commit();
// To store secret ID string of file or folder so that we can later get a DriveId object.
realid = sky.getDriveFolder().getDriveId().encodeToString();
sp.edit().putString(folderid, realid).commit();
showToast("Real== "+realid);
}
DriveId retid = DriveId.decodeFromString(sp.getString(folderid, ""));
DriveFolder folder = Drive.DriveApi.getFolder(getGoogleApiClient(), retid);
MetadataChangeSet changeSet2 = new MetadataChangeSet.Builder()
.setTitle("New folder")
.build();
MetadataResult res = folder.updateMetadata(getGoogleApiClient(), changeSet2).await();
showToast("Folder== "+folder.getDriveId().encodeToString());
showToast("folder created");
upladfile();
}
catch(Exception e)
{
showToast(""+e);
}
}
private void upladfile() {
// TODO Auto-generated method stub
String storedId=sp.getString(folderid, "");
DriveId retid = DriveId.decodeFromString(storedId);
DriveFolder skyfolder = Drive.DriveApi.getFolder(getGoogleApiClient(), retid);
contentsresult = Drive.DriveApi.newContents(mGoogleApiClient).await();
OutputStream outputStream = contentsresult.getContents().getOutputStream();
String s = Environment.getExternalStoragePublicDirectory("Download")
.getPath().toString();
showToast(s);
File file = new File(s + "/k.mp3");
showToast("Path=" + Environment.DIRECTORY_DOWNLOADS + "/k"
+ file.length());
buffer = new byte[(int) file.length()];
try {
showToast("started reading n writing");
outputStream.write(buffer);
showToast("Buffer is written");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
showToast("" + e.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
showToast("" + e.toString());
}
showToast("" + contentsresult.getContents().toString());
//DriveFolder fldr = Drive.DriveApi.getFolder(getGoogleApiClient(),sky.getDriveFolder().getDriveId());
MetadataChangeSet changeSet2 = new MetadataChangeSet.Builder()
.setTitle("New file").setMimeType("audio/MP3").setStarred(true)
.build();
showToast("meta data created");
DriveFileResult fileresult = skyfolder.createFile(getGoogleApiClient(),
changeSet2, contentsresult.getContents()).await();
songfileid = fileresult.getDriveFile().getDriveId().encodeToString();
showToast("file has been created "+fileresult.toString());
// Status stat = Drive.DriveApi.requestSync(mGoogleApiClient).await();
showToast("await() complete");
if (!contentsresult.getStatus().isSuccess()) {
showToast("Error while trying to create the file");
return;
}
add_to_db();
getvalues();
//String storedId=sp.getString(folderid, "");
DriveId fffid = DriveId.decodeFromString(dbfileid.get(0));
DriveFile fff = Drive.DriveApi.getFile(getGoogleApiClient(), fffid);
MetadataChangeSet changeSet3 = new MetadataChangeSet.Builder()
.setTitle("renamed")
.build();
MetadataResult res = fff.updateMetadata(getGoogleApiClient(), changeSet3).await();
if(res!=null)
{
showToast("renamed"+res.getMetadata().getTitle());
}
try {
//String iid=fffid.getResourceId();
service.files().delete(fffid.getResourceId()).execute();
showToast("Delete");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
protected void onActivityResult(final int requestCode,
final int resultCode, final Intent data) {
if (requestCode == REQUEST_CODE_RESOLUTION && resultCode == RESULT_OK) {
mGoogleApiClient.connect();
showToast("Connected");
}
}
#Override
protected void onPause() {
if (mGoogleApiClient != null) {
mGoogleApiClient.disconnect();
}
super.onPause();
}
public void showToast(final String toast) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), toast,
Toast.LENGTH_SHORT).show();
}
});
}
public GoogleApiClient getGoogleApiClient() {
return mGoogleApiClient;
}
public void add_to_db()
{
dbhelper=new fileiddb(this);
database=dbhelper.getWritableDatabase();
ContentValues values = new ContentValues();
String id =songfileid;
String name="k";
showToast("database id ="+id);
values.put(fileid,id);
values.put(filename,name);
database.insert(TABLE, null, values);
database.close();
Toast.makeText(this,"Added Successfully" ,Toast.LENGTH_LONG).show();
}
public void getvalues()
{
showToast("getting Values");
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE;
dbhelper=new fileiddb(this);
database=dbhelper.getWritableDatabase();
Cursor cursor = database.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
dbfileid.add(cursor.getString(0));
dbfilename.add(cursor.getString(1));
showToast("id=="+dbfileid.get(j).toString());
j++;
} while (cursor.moveToNext());
}
}
private com.google.api.services.drive.Drive getDriveService(GoogleAccountCredential credential) {
return new com.google.api.services.drive.Drive.Builder(AndroidHttp.newCompatibleTransport(), new GsonFactory(), credential)
.build();
}
#Override
public void onConnectionSuspended(int cause) {
showToast("GoogleApiClient connection suspended");
}
}
Except delete everything is working fine.
service.files().delete(fffid.getResourceId()).execute();
Any REST Api's .execute() (as well as GDAA's .await() flavored calls) must be run off UI thread. You should wrap it in:
new AsyncTask<Void, Void, Void>() {
#Override protected Integer doInBackground(String... params) {
//...
return null;
}
}.execute(); // .cancel(true);
or
new Thread(new Runnable() { #Override public void run() {
//....
}}).start();
Good Luck

Spring REST service: retrieving JSON from Request

I am building a REST service on Spring 3.1. I am using #EnableWebMVC annotation for that. Since my service will only be accepting JSON requests, I would also like to dump the incoming request into a MongoDB collection for logging (and, later, for data transformation). I would like to access the raw JSON Request (which I could do on a non-spring implementation using "#Content HttpServletRequest request" as a method parameter).
I am a Spring newbie. So, kindly help me with directions to achieve this. Thanks!
UPDATE: The issue is not completely resolved. Only my tests with GET worked. It fails with POST. Therefore unchecked the accepted answer
The issue is, even if I create a HttpServletRequestWrapper, I cannot forward the request after I process and wrap the request. Here is what happens:
Interceptor:
public class DBLogInterceptor extends HandlerInterceptorAdapter {
MyRequestWrapper requestWrapper;
private final static Logger logger = Logger.getLogger(DBLogInterceptor.class);
#Override
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception
{
requestWrapper = new MyRequestWrapper(request);
// Code removed, but it just dumps requestWrapper.getBody() into DB
return super.preHandle(requestWrapper, response, handler);
}
}
HTTP POST Servicing method
#RequestMapping(method = RequestMethod.POST, consumes="application/json", produces="application/json", value = "employee")
#ResponseBody
public String updateEntity(#RequestBody Employee emp) {
// Do some DB Stuff. Anyway, the control flow does not reach this place.
return "Employee " + emp.getName() + " updated successfully!";
}
Now I get an exception whenever I send a POST:
12:04:53,821 DEBUG DBLogInterceptor:22 - {"name":"Van Damme","dept":"Applied Martial Arts"}
12:04:53,843 DEBUG RequestResponseBodyMethodProcessor:117 - Reading [com.test.webapp.login.domain.Employee] as "application/json" using [org.springframework.http.converter.json.MappingJacksonHttpMessageConverter#154174f9]
12:04:53,850 DEBUG ExceptionHandlerExceptionResolver:132 - Resolving exception from handler [public java.lang.String com.test.webapp.controller.EmployeeService.updateEntity(com.test.webapp.login.domain.Employee)]: java.io.IOException: Stream closed
12:04:53,854 DEBUG ResponseStatusExceptionResolver:132 - Resolving exception from handler [public java.lang.String com.test.webapp.controller.EmployeeService.updateEntity(com.test.webapp.login.domain.Employee)]: java.io.IOException: Streamclosed
12:04:53,854 DEBUG DefaultHandlerExceptionResolver:132 - Resolving exception from handler [public java.lang.String com.test.webapp.controller.EmployeeService.updateEntity(com.test.webapp.login.domain.Employee)]: java.io.IOException: Streamclosed
12:04:53,859 DEBUG DispatcherServlet:910 - Could not complete request
java.io.IOException: Stream closed
at org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:312)
at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:200)
at org.codehaus.jackson.impl.ByteSourceBootstrapper.ensureLoaded(ByteSourceBootstrapper.java:507)
at org.codehaus.jackson.impl.ByteSourceBootstrapper.detectEncoding(ByteSourceBootstrapper.java:129)
at org.codehaus.jackson.impl.ByteSourceBootstrapper.constructParser(ByteSourceBootstrapper.java:224)
at org.codehaus.jackson.JsonFactory._createJsonParser(JsonFactory.java:785)
at org.codehaus.jackson.JsonFactory.createJsonParser(JsonFactory.java:561)
at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1914)
at org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.readInternal(MappingJacksonHttpMessageConverter.java:124)
at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:153)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:120)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:91)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:71)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:75)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:156)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:117)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:999)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:565)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:307)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
I expected the HttpServletRequestWrapper to be taking care of caching the request. But it doesn't happen somehow.
Using the HttpServletRequest object, you can get access to the URL the client used to make the request, the method used (GET, POST, PUT, etc), the query string, and headers.
Getting the RequestBody may be a bit trickier and may require using the HttpServletRequestWrapper object. Since the request body can only be read once, you'll need to extend the wrapper to access it so that your target controller can still access it later to deserialize your JSON into POJO objects.
public class MyRequestWrapper extends HttpServletRequestWrapper {
private final String body;
public MyRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
throw ex;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
throw ex;
}
}
}
body = stringBuilder.toString();
}
#Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
ServletInputStream servletInputStream = new ServletInputStream() {
public int read() throws IOException {
return byteArrayInputStream.read();
}
};
return servletInputStream;
}
#Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
public String getBody() {
return this.body;
}
}
To access the requests in a central location, you can use either a Filter or a Spring Interceptor. Both of these are invoked prior to the request being delegated to the controller, and both have access to the servlet.
Here is an actual Logging example using a Spring Interceptor:
package com.vaannila.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler. HandlerInterceptorAdapter;
public class LoggerInterceptor extends HandlerInterceptorAdapter {
static Logger logger = Logger.getLogger(LoggerInterceptor.class);
static {
BasicConfigurator.configure();
}
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
logger.info("Before handling the request");
return super.preHandle(request, response, handler);
}
#Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
logger.info("After handling the request");
super.postHandle(request, response, handler, modelAndView);
}
#Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
logger.info("After rendering the view");
super.afterCompletion(request, response, handler, ex);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="viewResolver" class="org.springframework.web.servlet.view. InternalResourceViewResolver" p:prefix="/WEB-INF/jsp/" p:suffix=".jsp" />
<bean id="handlerMapping" class="org.springframework.web.servlet.handler. BeanNameUrlHandlerMapping" p:interceptors-ref="loggerInterceptor" />
<bean id="loggerInterceptor" class="com.vaannila.interceptor.LoggerInterceptor" />
<bean id="userService" class="com.vaannila.service.UserServiceImpl" />
<bean name="/userRegistration.htm" class="com.vaannila.web.UserController" p:userService-ref="userService" p:formView="userForm" p:successView="userSuccess" />
</beans>
In the LoggerInterceptor, you could use the following code to access the request:
MyRequestWrapper myRequestWrapper = new MyRequestWrapper((HttpServletRequest) request);
String body = myRequestWrapper.getBody();
String clientIP = myRequestWrapper.getRemoteHost();
int clientPort = request.getRemotePort();
String uri = myRequestWrapper.getRequestURI();
System.out.println(body);
System.out.println(clientIP);
System.out.println(clientPort);
System.out.println(uri);
I doubt if HttpServletRequestWrapper can ever work... Take a look at the DispatcherServlet implementation:
HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
if (interceptors != null) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
return;
}
interceptorIndex = i;
}
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
It passes reference to "processedRequest" still, which refers to a HttpServletRequest request whose stream has already been read.
I know this is an old question, but for those of you that are still looking for a solution, this worked for me:
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.output.TeeOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HttpLoggingFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(HttpLoggingFilter.class);
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
Map<String, String> requestMap = this
.getTypesafeRequestMap(httpServletRequest);
BufferedRequestWrapper bufferedRequest = new BufferedRequestWrapper(
httpServletRequest);
BufferedResponseWrapper bufferedResponse = new BufferedResponseWrapper(
httpServletResponse);
final StringBuilder logMessage = new StringBuilder(
"REST Request - ").append("[HTTP METHOD:")
.append(httpServletRequest.getMethod())
.append("] [PATH INFO:")
.append(httpServletRequest.getPathInfo())
.append("] [REQUEST PARAMETERS:").append(requestMap)
.append("] [REQUEST BODY:")
.append(bufferedRequest.getRequestBody())
.append("] [REMOTE ADDRESS:")
.append(httpServletRequest.getRemoteAddr()).append("]");
chain.doFilter(bufferedRequest, bufferedResponse);
logMessage.append(" [RESPONSE:")
.append(bufferedResponse.getContent()).append("]");
logger.debug(logMessage.toString());
} catch (Throwable a) {
logger.error(a.getMessage());
}
}
private Map<String, String> getTypesafeRequestMap(HttpServletRequest request) {
Map<String, String> typesafeRequestMap = new HashMap<String, String>();
Enumeration<?> requestParamNames = request.getParameterNames();
while (requestParamNames.hasMoreElements()) {
String requestParamName = (String) requestParamNames.nextElement();
String requestParamValue = request.getParameter(requestParamName);
typesafeRequestMap.put(requestParamName, requestParamValue);
}
return typesafeRequestMap;
}
#Override
public void destroy() {
}
private static final class BufferedRequestWrapper extends
HttpServletRequestWrapper {
private ByteArrayInputStream bais = null;
private ByteArrayOutputStream baos = null;
private BufferedServletInputStream bsis = null;
private byte[] buffer = null;
public BufferedRequestWrapper(HttpServletRequest req)
throws IOException {
super(req);
// Read InputStream and store its content in a buffer.
InputStream is = req.getInputStream();
this.baos = new ByteArrayOutputStream();
byte buf[] = new byte[1024];
int read;
while ((read = is.read(buf)) > 0) {
this.baos.write(buf, 0, read);
}
this.buffer = this.baos.toByteArray();
}
#Override
public ServletInputStream getInputStream() {
this.bais = new ByteArrayInputStream(this.buffer);
this.bsis = new BufferedServletInputStream(this.bais);
return this.bsis;
}
String getRequestBody() throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(
this.getInputStream()));
String line = null;
StringBuilder inputBuffer = new StringBuilder();
do {
line = reader.readLine();
if (null != line) {
inputBuffer.append(line.trim());
}
} while (line != null);
reader.close();
return inputBuffer.toString().trim();
}
}
private static final class BufferedServletInputStream extends
ServletInputStream {
private ByteArrayInputStream bais;
public BufferedServletInputStream(ByteArrayInputStream bais) {
this.bais = bais;
}
#Override
public int available() {
return this.bais.available();
}
#Override
public int read() {
return this.bais.read();
}
#Override
public int read(byte[] buf, int off, int len) {
return this.bais.read(buf, off, len);
}
}
public class TeeServletOutputStream extends ServletOutputStream {
private final TeeOutputStream targetStream;
public TeeServletOutputStream(OutputStream one, OutputStream two) {
targetStream = new TeeOutputStream(one, two);
}
#Override
public void write(int arg0) throws IOException {
this.targetStream.write(arg0);
}
public void flush() throws IOException {
super.flush();
this.targetStream.flush();
}
public void close() throws IOException {
super.close();
this.targetStream.close();
}
}
public class BufferedResponseWrapper implements HttpServletResponse {
HttpServletResponse original;
TeeServletOutputStream tee;
ByteArrayOutputStream bos;
public BufferedResponseWrapper(HttpServletResponse response) {
original = response;
}
public String getContent() {
return bos.toString();
}
public PrintWriter getWriter() throws IOException {
return original.getWriter();
}
public ServletOutputStream getOutputStream() throws IOException {
if (tee == null) {
bos = new ByteArrayOutputStream();
tee = new TeeServletOutputStream(original.getOutputStream(),
bos);
}
return tee;
}
#Override
public String getCharacterEncoding() {
return original.getCharacterEncoding();
}
#Override
public String getContentType() {
return original.getContentType();
}
#Override
public void setCharacterEncoding(String charset) {
original.setCharacterEncoding(charset);
}
#Override
public void setContentLength(int len) {
original.setContentLength(len);
}
#Override
public void setContentType(String type) {
original.setContentType(type);
}
#Override
public void setBufferSize(int size) {
original.setBufferSize(size);
}
#Override
public int getBufferSize() {
return original.getBufferSize();
}
#Override
public void flushBuffer() throws IOException {
tee.flush();
}
#Override
public void resetBuffer() {
original.resetBuffer();
}
#Override
public boolean isCommitted() {
return original.isCommitted();
}
#Override
public void reset() {
original.reset();
}
#Override
public void setLocale(Locale loc) {
original.setLocale(loc);
}
#Override
public Locale getLocale() {
return original.getLocale();
}
#Override
public void addCookie(Cookie cookie) {
original.addCookie(cookie);
}
#Override
public boolean containsHeader(String name) {
return original.containsHeader(name);
}
#Override
public String encodeURL(String url) {
return original.encodeURL(url);
}
#Override
public String encodeRedirectURL(String url) {
return original.encodeRedirectURL(url);
}
#SuppressWarnings("deprecation")
#Override
public String encodeUrl(String url) {
return original.encodeUrl(url);
}
#SuppressWarnings("deprecation")
#Override
public String encodeRedirectUrl(String url) {
return original.encodeRedirectUrl(url);
}
#Override
public void sendError(int sc, String msg) throws IOException {
original.sendError(sc, msg);
}
#Override
public void sendError(int sc) throws IOException {
original.sendError(sc);
}
#Override
public void sendRedirect(String location) throws IOException {
original.sendRedirect(location);
}
#Override
public void setDateHeader(String name, long date) {
original.setDateHeader(name, date);
}
#Override
public void addDateHeader(String name, long date) {
original.addDateHeader(name, date);
}
#Override
public void setHeader(String name, String value) {
original.setHeader(name, value);
}
#Override
public void addHeader(String name, String value) {
original.addHeader(name, value);
}
#Override
public void setIntHeader(String name, int value) {
original.setIntHeader(name, value);
}
#Override
public void addIntHeader(String name, int value) {
original.addIntHeader(name, value);
}
#Override
public void setStatus(int sc) {
original.setStatus(sc);
}
#SuppressWarnings("deprecation")
#Override
public void setStatus(int sc, String sm) {
original.setStatus(sc, sm);
}
#Override
public String getHeader(String arg0) {
return original.getHeader(arg0);
}
#Override
public Collection<String> getHeaderNames() {
return original.getHeaderNames();
}
#Override
public Collection<String> getHeaders(String arg0) {
return original.getHeaders(arg0);
}
#Override
public int getStatus() {
return original.getStatus();
}
}
}
Then simply register the filter in web.xml and you're done. All credits to: http://wetfeetblog.com/servlet-filer-to-log-request-and-response-details-and-payload/431 (I just did some minor fix to it).
Hey can you try with this:
#RequestMapping(method = RequestMethod.POST, consumes="application/json", produces="application/json", value = "/employee")
#ResponseBody
public String updateEntity(#RequestBody Employee emp) {
// Do some DB Stuff. Anyway, the control flow does not reach this place.
return "Employee " + emp.getName() + " updated successfully!";
}
Here: it you proving URI with the '/' it allows all the operations to perform. such as get post update and delete with same URI value.
Currently in spring-mvc repo, interceptors are invoked in DispatcherServlet#doDispatch(...):
https://github.com/spring-projects/spring-framework/blob/master/spring-webmvc/src/main/java/org/springframework/web/servlet/DispatcherServlet.java
...
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
try {
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
}
applyDefaultViewName(request, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
...
Can I define my own DispatcherServlet, and override doDispatch(...) to inject a HttpRequestWrapper with a ByteArrayInputStream on getInputStream()?
...
#Override
protected void doDispatch(HttpServletRequest request, HttpServletResponse response)
throws Exception {
RequestWrapper wrappedRequest = new RequestWrapper(request);
logger.debug("injecting RequestWrapper: " + wrappedRequest);
super.doDispatch(wrappedRequest, response);
}
...
Will this work for the above situation?
I make a Ouputstream version without any dependency to 3rd party libs for easier re-use. You can use this 2 wrapper class to get the request & response body easily.
But anyway, I have to use a filter to do this instead of interceptor. Because as #user1323865 mentioned, in spring 4, the processedRequest is used in both interceptor and handler, so you cannot use these methods for interceptor.
Also you can find some help in this link if you're using Writer version instead.
Capture and log the response body
public class BufferedRequestWrapper extends HttpServletRequestWrapper
{
private static final class BufferedServletInputStream extends ServletInputStream
{
private ByteArrayInputStream bais;
public BufferedServletInputStream(ByteArrayInputStream bais)
{
this.bais = bais;
}
#Override
public int available()
{
return this.bais.available();
}
#Override
public int read()
{
return this.bais.read();
}
#Override
public int read(byte[] buf, int off, int len)
{
return this.bais.read(buf, off, len);
}
}
private byte[] mBodyBuffer;
public BufferedRequestWrapper(HttpServletRequest request) throws IOException
{
super(request);
InputStream in = request.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int bytesRead = -1;
while ((bytesRead = in.read(buffer)) > 0)
{
baos.write(buffer, 0, bytesRead);
}
mBodyBuffer = baos.toByteArray();
}
public String getRequestBody()
{
return new String(mBodyBuffer, Charset.forName("UTF-8"));
}
#Override
public BufferedReader getReader() throws IOException
{
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
#Override
public ServletInputStream getInputStream()
{
ByteArrayInputStream in = new ByteArrayInputStream(mBodyBuffer);
return new BufferedServletInputStream(in);
}
}
public class BufferedResponseWrapper extends HttpServletResponseWrapper
{
private TeeServletOutputStream mTeeOutputStream;
private static class TeeOutputStream extends OutputStream
{
private OutputStream mChainStream;
private OutputStream mTeeStream;
public TeeOutputStream(OutputStream chainStream, OutputStream teeStream)
{
mChainStream = chainStream;
mTeeStream = teeStream;
}
#Override
public void write(int b) throws IOException
{
mChainStream.write(b);
mTeeStream.write(b);
mTeeStream.flush();
}
#Override
public void close() throws IOException
{
flush();
mChainStream.close();
mTeeStream.close();
}
#Override
public void flush() throws IOException
{
mChainStream.close();
}
}
public class TeeServletOutputStream extends ServletOutputStream
{
private final TeeOutputStream targetStream;
public TeeServletOutputStream(OutputStream one, OutputStream two)
{
targetStream = new TeeOutputStream(one, two);
}
#Override
public void write(int b) throws IOException
{
this.targetStream.write(b);
}
#Override
public void flush() throws IOException
{
super.flush();
this.targetStream.flush();
}
#Override
public void close() throws IOException
{
super.close();
this.targetStream.close();
}
}
private ByteArrayOutputStream mByteArrayOutputStream;
public BufferedResponseWrapper(HttpServletResponse response) throws IOException
{
super(response);
mByteArrayOutputStream = new ByteArrayOutputStream();
mTeeOutputStream = new TeeServletOutputStream(super.getResponse().getOutputStream(), mByteArrayOutputStream);
}
#Override
public PrintWriter getWriter() throws IOException
{
return super.getResponse().getWriter();
}
#Override
public ServletOutputStream getOutputStream() throws IOException
{
return mTeeOutputStream;
}
public String getResponseBody()
{
return mByteArrayOutputStream.toString();
}
}
One simple way to do this would be to get the request body as String and then parse as a Java object. You can use this String then as you want.
So in your example:
#RequestMapping(method = RequestMethod.POST, consumes="application/json", produces="application/json", value = "employee")
#ResponseBody
public String updateEntity(#RequestBody String empAsString) {
// Do whatever with the json as String
System.out.println(empAsString);
// Transform it into the Java Object you want
ObjectMapper mapper = new ObjectMapper();
Employee emp = mapper.readValue(empAsString, Employee.class);
// Do some DB Stuff. Anyway, the control flow does not reach this place.
return "Employee " + emp.getName() + " updated successfully!";
}
As a note, if you need it as a list you can use:
List<Employee> eventsList =
mapper.readValue(jsonInString, mapper.getTypeFactory().constructCollectionType(List.class, Employee.class));
You need to implement the requestWrapper as follows:
public class DocVerificationRequestWrapper extends HttpServletRequestWrapper {
private final String body;
public DocVerificationRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
throw ex;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
throw ex;
}
}
}
body = stringBuilder.toString();
}
#Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
ServletInputStream servletInputStream = new ServletInputStream() {
public int read() throws IOException {
return byteArrayInputStream.read();
}
#Override
public boolean isFinished() {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean isReady() {
// TODO Auto-generated method stub
return false;
}
#Override
public void setReadListener(ReadListener listener) {
// TODO Auto-generated method stub
}
};
return servletInputStream;
}
#Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
public String getBody() {
return this.body;
}
}
and then inside the chain.doFilter method of filter class pass the requestWrapper object instead of the request object as follows:
#Override
public void doFilter(ServletRequest arg0, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
logger.info("checking token in filter");
HttpServletRequest request = (HttpServletRequest) arg0;
DocVerificationRequestWrapper myRequestWrapper = new DocVerificationRequestWrapper((HttpServletRequest) request);
String body = myRequestWrapper.getBody();
logger.info("body = "+body);
Token token = null;
try {
JSONObject jsonObj = new JSONObject(body);
JSONObject tokenObj = (JSONObject) jsonObj.get("token");
Gson gson = new Gson();
token = gson.fromJson(tokenObj.toString(), Token.class);
if(null != token) {
if(userVerificationService==null){
ServletContext servletContext = request.getServletContext();
WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
userVerificationService = webApplicationContext.getBean(UserVerificationService.class);
}
String verStatus = userVerificationService.verifyUser(token);
logger.info("verStatus = "+verStatus);
if(verStatus != null && verStatus.equalsIgnoreCase("success")) {
chain.doFilter(myRequestWrapper, response); //here replacing request with requestWrapper
}else
logger.error("Invalid token");
}else {
logger.error("token missing.");
}
} catch (JSONException e) {
logger.error("exception in authetication filter " + e);
}
}
Thus solving the IOStream closed exception.
For getting data from Body you can try to read and recreate InputStream in RequestBodyAdviceAdapter:
#ControllerAdvice
public class CustomRequestBodyAdviceAdapter extends RequestBodyAdviceAdapter {
#Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
String body = IOUtils.toString(inputMessage.getBody(), UTF_8.name());
HttpInputMessage myMessage = new HttpInputMessage(){
#Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream(body.getBytes());
}
#Override
public HttpHeaders getHeaders() {
return inputMessage.getHeaders();
}
};
System.out.println("Data from Body: " + body);
return super.beforeBodyRead(myMessage, parameter, targetType, converterType);
}
#Override
public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
System.out.println("Data from Body is empty");
return super.handleEmptyBody(body, inputMessage, parameter, targetType, converterType);
}
#Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return super.afterBodyRead(body, inputMessage, parameter, targetType, converterType);
}
#Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
}
You can simply use :
import org.apache.commons.io.IOUtils;
import java.nio.charset.Charset;
String requestBody = IOUtils.toString(request.getInputStream(), Charset.forName("UTF-8").toString());
In my experiences,just develop as follows:
Using the filter in order to wrapper ServletRequest,then you can repeatly use getting request input stream.