Getting the roles of a user in wso2 - java

I've created users and assigned them different roles using wso2im. Using these I managed to restrict access to a .jsp file so roles seem to be working right.
The problem lies when I need to display different things to different roles within the same JSP (For instance, role AAA can do xxx and yyy, role BBB can do zzz), I'm trying to check for roles using request.isUserInRole("role") but it always returns null, both when trying from the .jsp itself and the servlet that handles authentication.

Finally managed to get it to work. Getting the roles with the servlet and storing them in a cookie. Neither safe nor pretty but does the job:
package foo;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;
import org.apache.axis2.transport.http.HttpTransportProperties;
import org.apache.axis2.client.Options;
import org.apache.axis2.transport.http.HTTPConstants;
import org.wso2.carbon.um.ws.api.stub.RemoteUserStoreManagerServiceStub;
/**
* Servlet implementation class LoginServlet
*/
#WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private final String basicAuthUserID = "admin";
private final String basicAuthPassword = "admin";
private final String serverUrl = "https://localhost:9444/services/";
private RemoteUserStoreManagerServiceStub stub = null;
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// get request parameters for userID and password
String user = request.getParameter("user");
String pwd = request.getParameter("pwd");
try {
if(authenticate(user,pwd)){
HttpSession session = request.getSession();
session.setAttribute("user", user);
//setting session to expiry in 30 mins
session.setMaxInactiveInterval(30*60);
Cookie userName = new Cookie("user", user);
userName.setMaxAge(30*60);
String[] roles = getRoleListOfUser(user);
String rolesTodos = null;
for (String s: roles){
if (!s.equals("Internal/everyone")) {
if (rolesTodos == null){
rolesTodos = s;
} else {
//System.out.println("Rol: " + s);
rolesTodos = rolesTodos + "," + s;
}
}
}
//System.out.println("Roles: " + rolesTodos);
Cookie rolesCookie = new Cookie("roles", rolesTodos);
rolesCookie.setMaxAge(30*60);
response.addCookie(userName);
response.addCookie(rolesCookie);
response.sendRedirect("index.jsp");
}else{
RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.html");
PrintWriter out= response.getWriter();
out.println("<font color=red>Either user name or password is wrong.</font>");
rd.include(request, response);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private boolean authenticate(String userName, Object credential) throws Exception {
if (!(credential instanceof String)) {
throw new Exception("Unsupported type of password");
}
try {
if(stub == null) {
stub = new RemoteUserStoreManagerServiceStub(null, serverUrl
+ "RemoteUserStoreManagerService");
HttpTransportProperties.Authenticator basicAuth = new HttpTransportProperties.Authenticator();
basicAuth.setUsername(basicAuthUserID);
basicAuth.setPassword(basicAuthPassword);
basicAuth.setPreemptiveAuthentication(true);
final Options clientOptions = stub._getServiceClient().getOptions();
clientOptions.setProperty(HTTPConstants.AUTHENTICATE, basicAuth);
stub._getServiceClient().setOptions(clientOptions);
}
return stub.authenticate(userName, (String) credential);
} catch (Exception e) {
handleException(e.getMessage(), e);
}
return false;
}
private String[] handleException(String msg, Exception e) throws Exception {
System.out.println(e.getMessage() + e);
throw new Exception(msg, e);
}
public String[] getRoleListOfUser(String userName) throws Exception {
try {
return stub.getRoleListOfUser(userName);
} catch (Exception e) {
System.out.println(e.getMessage() + e);
}
return null;
}
}

Related

How to use SAML token attributes value inside my JAAS custom login module in Websphere 8.5.5

I am using a custom JAAS login module for achieve the idAssertion. I have already a valid TAI configured which will get the SAML response back with token data or attributes value. I need to use the groups details in my JAAS login module from SAML token. How can I get the groups and attribute value here? Already use WSSUtilFactory but it return null value.
JAAS Log in module
package com.hcl.portal.transparent;
import java.security.PrivilegedActionException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.naming.InitialContext;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;
import com.ibm.portal.auth.tai.ExternalIdentityCredential;
import com.ibm.websphere.security.UserRegistry;
import com.ibm.websphere.security.WSSecurityException;
import com.ibm.websphere.security.auth.WSSubject;
import com.ibm.websphere.wssecurity.wssapi.WSSUtilFactory;
import com.ibm.websphere.wssecurity.wssapi.token.SAMLToken;
import com.ibm.ws.security.util.AccessController;
import com.ibm.wsspi.security.auth.callback.WSTokenHolderCallback;
import com.ibm.wsspi.security.token.AttributeNameConstants;
import com.ibm.wsspi.wssecurity.saml.data.SAMLAttribute;
import com.ibm.wsspi.wssecurity.saml.data.SAMLNameID;
public class loginModule implements LoginModule {
private boolean success = false;
Subject currentSubject;
CallbackHandler currentCallbackHandler;
Map<String, Object> currentSharedState;
Map<String, Object> currentOptions;
#Override
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map<String, ?> sharedState, Map<String, ?> options) {
currentSubject = subject;
currentCallbackHandler = callbackHandler;
currentSharedState = (Map<String, Object>) sharedState;
currentOptions = (Map<String, Object>) options;
success = false;
System.out.println("kousik level 0.1");
}
#Override
public boolean login() throws LoginException {
String uniqueid = "";
Hashtable hashtable = new Hashtable();
Callback callbacks[] = new Callback[3];
System.out.println("kousik level 0.2");
try {
callbacks[0] = new WSTokenHolderCallback("");
callbacks[1] = new NameCallback("User:");
callbacks[2] = new PasswordCallback("Password:", false);
currentCallbackHandler.handle(callbacks);
boolean requiresLogin = ((WSTokenHolderCallback) callbacks[0]).getRequiresLogin();
if (requiresLogin) {
String username = ((NameCallback) callbacks[1]).getName();
String userDefaultname = ((NameCallback) callbacks[1]).getDefaultName();
System.out.println("k----------username = " + username);
System.out.println("k----------Dusername = " + userDefaultname);
if (username != null) {
try {
InitialContext ctx = new InitialContext();
UserRegistry reg = (UserRegistry) ctx.lookup("UserRegistry");
uniqueid = reg.getUniqueUserId(username);
} catch (com.ibm.websphere.security.EntryNotFoundException e1) {
System.out.println("Login Module - transient for base realm ");
uniqueid = "uid=" + username + ",o=base,o=transparent";
hashtable.put(AttributeNameConstants.WSCREDENTIAL_UNIQUEID,uniqueid);
hashtable.put(AttributeNameConstants.WSCREDENTIAL_SECURITYNAME,uniqueid);
// You may add specific users to specific groups to not only have all transient user as "AllAuthenticated"
ArrayList<String> groupList = new ArrayList<String>();
groupList.add("cn=wpsadmins,o=defaultWIMFileBasedRealm");
// AttributeNameConstants.WSCREDENTIAL_GROUPS
hashtable.put(AttributeNameConstants.WSCREDENTIAL_GROUPS,groupList);
// Add attributes for this special user as well
hashtable.put("sn",username);
hashtable.put("cn",username);
hashtable.put("uid",username);
hashtable.put("ibm-primaryEmail",username+"#portal.ibm.com");
// }
currentSubject.getPublicCredentials().add(hashtable);
currentSubject.getPublicCredentials().add(new ExternalIdentityCredential(hashtable));
currentSharedState.put(AttributeNameConstants.WSCREDENTIAL_PROPERTIES_KEY,hashtable);
} catch (Exception e1) {
System.out.println("Login Module failed for user lookup: "+ e1);
}
System.out.println("uniqueid = " + uniqueid);
} else {
System.out.println("uniqueid is null - do nothing");
success = false;
System.out.println("failed with uniqueid= " + uniqueid);
return success;
}
} else {
System.out.println("This is a repeat login, nothing to do.");
}
} catch (Exception e) {
System.out.println("Login Module failed: " + e);
}
success = true;
System.out.println("success with uniqueid= " + uniqueid);
return success;
}
#Override
public boolean commit() throws LoginException {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean abort() throws LoginException {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean logout() throws LoginException {
// TODO Auto-generated method stub
return false;
}
}

Quartz job not restarting in java web

I am implementing a module to take the screenshot of logged in user after every 3 minutes.
This module works fine
But the problem I am facing is that whenever i logged in the user the job starts as it intends to do, but on the logout I shuts down the scheduler. But now the next time i try to login back now scheduler initialized but job isn't starting. I need to redeploy project again for next run.
Here is my LoginBean.java class from where I am starting the job.
package com.viremp.beans;
import java.awt.AWTException;
import java.io.IOException;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.viremp.component.HandleHobs;
#ManagedBean
#SessionScoped
public class LoginBean implements Serializable {
/**
*
*/
private static final long serialVersionUID = -8650636789236091591L;
private static Logger LOGGER = LoggerFactory.getLogger(LoginBean.class);
private String username;
private String password;
private String error;
private boolean visible = false;
private HandleHobs handleHobs;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public boolean isVisible() {
return visible;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
/*
* public LoginBean() { try { if (handleHobs != null &&
* !handleHobs.isJobStoredScreenShotIsStarted()) { handleHobs = new
* HandleHobs(); } } catch (Exception e) { LOGGER.error("error init job", e); }
*
* }
*/
#PostConstruct
public void init() {
try {
if (handleHobs == null || !handleHobs.isJobStoredScreenShotIsStarted()) {
handleHobs = new HandleHobs();
}
} catch (Exception e) {
LOGGER.error("error init job", e);
}
}
public void login() throws ClassNotFoundException, SQLException, IOException, AWTException {
// String un = "a";
// String pw = "b";
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext externalContext = context.getExternalContext();
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
// Login login = new Login();
// boolean isLoggedIn = login.LoginUser(username, password);
try {
request.login(username, password);
handleHobs.startJobStoredScreenShot(username);
externalContext
.redirect(externalContext.getRequestContextPath() + "/faces/Success.xhtml?faces-redirect=true");
} catch (Exception e) {
FacesContext fc = FacesContext.getCurrentInstance();
this.error = getErrorParam(fc);
setVisible(true);
System.out.println("not equal.. " + error);
e.printStackTrace();
}
/*
*
* if (isLoggedIn) { System.out.println("equal"); externalContext
* .redirect(externalContext.getRequestContextPath() +
* "/faces/Success.xhtml?faces-redirect=true"); } else {
*
* FacesContext fc = FacesContext.getCurrentInstance(); this.error =
* getErrorParam(fc);
*
* setVisible(true); System.out.println("not equal.. " + error);
*
* }
*/
}
public String getErrorParam(FacesContext fc) {
Map<String, String> params = fc.getExternalContext().getRequestParameterMap();
return params.get("error1");
}
public logout(){
handleHobs.shutdownJobStoredScreenShot();
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
externalContext.invalidateSession();
externalContext.redirect(externalContext.getRequestContextPath() + "/faces/login.xhtml?faces-redirect=true");
}
And here is my HandleHobs.java class which is for handling job, [sorry for the wrong class name, it should be HandleJobs.java]
package com.viremp.component;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HandleHobs {
private static Logger LOGGER = LoggerFactory.getLogger(HandleHobs.class);
private static JobDetail job;
private static Scheduler scheduler;
String email;
public HandleHobs(String email) {
this.email = email;
}
private static Trigger trigger;
{
try {
if (job == null && scheduler == null && trigger == null) {
LOGGER.info("initializing job");
job = (JobDetail) newJob(JobStoredScreenShot.class).withIdentity("job1", "group1").build();
trigger = newTrigger().withIdentity("trigger1", "group1").startNow()
.withSchedule(simpleSchedule().withIntervalInSeconds(5).repeatForever()).build();
scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.scheduleJob(job, trigger);
LOGGER.info("init successsful");
}
} catch (Exception e) {
LOGGER.error("fail to init variables for job", e);
}
}
public HandleHobs() {
}
public void startJobStoredScreenShot(String email) {
try {
this.email = email;
JobStoredScreenShot jss = new JobStoredScreenShot();
jss.setEmail(email);
if (scheduler != null && !scheduler.isStarted()) {
Scheduler scheduler1 = new StdSchedulerFactory().getScheduler();
System.out.println("here..... " + email);
scheduler1.getContext().put("email", email);
System.out.println("and here..... " + email);
scheduler.start();
}
LOGGER.info("init successsful");
} catch (Exception e) {
LOGGER.error("fail to init job JobStoredScreenShot", e);
}
}
public void shutdownJobStoredScreenShot() {
try {
if (scheduler.isStarted()) {
scheduler.shutdown();
}
LOGGER.info("shutdown successsful");
} catch (Exception e) {
LOGGER.error("fail to init job JobStoredScreenShot", e);
}
}
public boolean isJobStoredScreenShotIsStarted() {
boolean isStarted = false;
try {
if (scheduler != null) {
isStarted = true;
}
} catch (Exception e) {
LOGGER.error("fail get isTarted", e);
}
return isStarted;
}
}
And here it is my JobStoredScreenShot.java class
package com.viremp.component;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.time.LocalDate;
import javax.imageio.ImageIO;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerContext;
import com.viremp.core.domain.Screenshot;
import com.viremp.core.domain.User;
import com.viremp.core.repository.ScreenshotRepository;
import com.viremp.core.repository.UserRepository;
import com.viremp.core.repository.impl.ScreenshotRepositoryImpl;
import com.viremp.core.repository.impl.UserRepositoryImpl;
public class JobStoredScreenShot implements Job {
String email;
User user = new User();
public void setEmail(String Email) {
this.email = Email;
System.out.println("in job stored class email is: " + email);
user.setEmail(email);
}
#Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
try {
SchedulerContext schedulerContext = arg0.getScheduler().getContext();
// Below line gets the value from context.
// Just get it and cast it in to correct type
String email = (String) schedulerContext.get("email");
System.out.println(email);
BufferedImage image = new Robot()
.createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "png", baos);
baos.flush();
byte[] imageInByte = baos.toByteArray();
baos.close();
System.out.println("in execute " + user.getEmail() + ".................: " + email);
UserRepository userRepository = new UserRepositoryImpl();
user = userRepository.getUserByEmail(email);
System.out.println("USER IS: " + user.getUsername() + " id is : " + user.getId());
// byte[] buffer = (((DataBufferByte)
// (image).getRaster().getDataBuffer()).getData());
InputStream inputStream = new ByteArrayInputStream(imageInByte);
LocalDate localDate = LocalDate.now();
Screenshot screenshot = new Screenshot();
screenshot.setInput(inputStream);
screenshot.setScreenshotName(user.getUsername());
screenshot.setUser(new User());
screenshot.getUser().setId(user.getId());
screenshot.setScreenShotTime(java.sql.Date.valueOf(localDate));
System.out.println("id is " + 1l);
ScreenshotRepository screenshotRepository = new ScreenshotRepositoryImpl();
screenshotRepository.create(screenshot);
ImageIO.write(image, "png", new File("d:\\screenshot.png"));
System.out.println("screenshot taken");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Please Help, Thanks
I have solved this issue by making job and scheduler null after shutting down the scheduler.
Here is the working code of HandleHobs.java
package com.viremp.component;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HandleHobs {
private static Logger LOGGER = LoggerFactory.getLogger(HandleHobs.class);
private static JobDetail job;
private static Scheduler scheduler;
String email;
// SchedulerFactory schedFact = new org.quartz.impl.StdSchedulerFactory();
public HandleHobs(String email) {
this.email = email;
}
private static Trigger trigger;
{
try {
LOGGER.info("initializing job");
job = (JobDetail) newJob(JobStoredScreenShot.class).withIdentity("job1", "group1").build();
trigger = newTrigger().withIdentity("trigger1", "group1").startNow()
.withSchedule(simpleSchedule().withIntervalInSeconds(5).repeatForever()).build();
scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.scheduleJob(job, trigger);
LOGGER.info("init successsful 1");
} catch (Exception e) {
LOGGER.error("fail to init variables for job", e);
}
}
public HandleHobs() {
}
public void startJobStoredScreenShot(String email) {
try {
System.out.println("yaar ma aa gaya hun");
this.email = email;
JobStoredScreenShot jss = new JobStoredScreenShot();
jss.setEmail(email);
if (scheduler != null && !scheduler.isStarted()) {
Scheduler scheduler1 = new StdSchedulerFactory().getScheduler();
System.out.println("here..... " + email);
scheduler1.getContext().put("email", email);
System.out.println("and here..... " + email);
scheduler.start();
}
LOGGER.info("init successsful");
} catch (Exception e) {
LOGGER.error("fail to init job JobStoredScreenShot", e);
}
}
public void shutdownJobStoredScreenShot() {
try {
if (scheduler.isStarted()) {
// JobExecutionContext context = new JobExecutionContext();
// JobKey key = context.getJobDetail().getKey();
// String jobId = key.getName();
// System.out.println("```````````````````NAME``````````````````````" + jobId);
// flag = true;
scheduler.shutdown();
scheduler = null; //i made it null here
job = null; // i made it null here
}
LOGGER.info("shutdown successsful");
} catch (Exception e) {
LOGGER.error("fail to init job JobStoredScreenShot", e);
}
}
public boolean isJobStoredScreenShotIsStarted() {
boolean isStarted = false;
try {
if (scheduler != null) {
isStarted = true;
}
} catch (Exception e) {
LOGGER.error("fail get isTarted", e);
}
return isStarted;
}
}
And this is my LoginBean.java from where I am initiating the job.
package com.viremp.beans;
import java.awt.AWTException;
import java.io.IOException;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.viremp.component.HandleHobs;
#ManagedBean
#SessionScoped
public class LoginBean implements Serializable {
/**
*
*/
private static final long serialVersionUID = -8650636789236091591L;
private static Logger LOGGER = LoggerFactory.getLogger(LoginBean.class);
private String username;
private String password;
private String error;
private boolean visible = false;
private HandleHobs handleHobs;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public boolean isVisible() {
return visible;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
/*
* public LoginBean() { try { if (handleHobs != null &&
* !handleHobs.isJobStoredScreenShotIsStarted()) { handleHobs = new
* HandleHobs(); } } catch (Exception e) { LOGGER.error("error init job", e); }
*
* }
*/
#PostConstruct
public void init() {
try {
handleHobs = new HandleHobs();
} catch (Exception e) {
LOGGER.error("error init job", e);
}
}
public void login() throws ClassNotFoundException, SQLException, IOException, AWTException {
// String un = "a";
// String pw = "b";
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext externalContext = context.getExternalContext();
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
// Login login = new Login();
// boolean isLoggedIn = login.LoginUser(username, password);
try {
request.login(username, password);
handleHobs.startJobStoredScreenShot(username);
externalContext
.redirect(externalContext.getRequestContextPath() + "/faces/Success.xhtml?faces-redirect=true");
} catch (Exception e) {
FacesContext fc = FacesContext.getCurrentInstance();
this.error = getErrorParam(fc);
setVisible(true);
System.out.println("not equal.. " + error);
e.printStackTrace();
}
/*
*
* if (isLoggedIn) { System.out.println("equal"); externalContext
* .redirect(externalContext.getRequestContextPath() +
* "/faces/Success.xhtml?faces-redirect=true"); } else {
*
* FacesContext fc = FacesContext.getCurrentInstance(); this.error =
* getErrorParam(fc);
*
* setVisible(true); System.out.println("not equal.. " + error);
*
* }
*/
}
public void logout() {
System.out.println("in logotu");
handleHobs.shutdownJobStoredScreenShot();
this.handleHobs = null; // here i also made null
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
externalContext.invalidateSession();
try {
externalContext
.redirect(externalContext.getRequestContextPath() + "/faces/Login.xhtml?faces-redirect=true");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String getErrorParam(FacesContext fc) {
Map<String, String> params = fc.getExternalContext().getRequestParameterMap();
return params.get("error1");
}
}
Actually after shutting down the jobs did shutdown the scheduler but did not empty the job and scheduler, so on next login the scheduler and job keeps the value so that the job was not starting again, so i just made the values null on shutdown.

Database connection suffers of concurrent threads

I've recently starting working on a java webapp (JSP / Servlet) that was developed by the internal developer of a company.
This app randomly doesn't return data, and inspecting the log I found some NullPointerExceptions related to the classes' member variable which holds the database connection. Following the stack trace it seems that a second thread closes the connection after it ended its task leaving the first thread without a connection.
By the needs of the company the app uses different databases, one which rules appdata, and others which contain data the app has to retrieve. So every class attached to the main servlet may connect to one or more databases depending on the task it has to accomplish.
I'm not familiar with JavaEE but giving a look at the database connection class, I see nothing which protect threads from conflicting each other.
Which is the correct way to handle such connections?
This is the code of the Database handler:
package it.metmi.mmasgis.utils;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class DBManager
{
private String szDatabase;
private String szUsername;
private String szPassword;
private String szError;
private Connection db;
private boolean bConnected;
private Logger logger;
public DBManager(String szDBName)
{
this(szDBName, "", "");
}
public DBManager(String szDBName, String szName, String szPass)
{
szDatabase = szDBName;
szUsername = szName;
szPassword = szPass;
bConnected = false;
szError = "";
logger = LogManager.getFormatterLogger(DBManager.class.getName());
}
public boolean connect()
{
logger.entry();
try {
Class.forName("com.mysql.jdbc.Driver");
if(!szDatabase.isEmpty())
{
String szCon = "jdbc:mysql://localhost/" + szDatabase;
if(!szUsername.isEmpty())
{
szCon += "?user=" + szUsername;
if(!szPassword.isEmpty())
szCon += "&password=" + szPassword;
}
db = DriverManager.getConnection(szCon);
bConnected = true;
} else {
logger.error("No database name!!");
System.exit(0);
}
} catch(SQLException | ClassNotFoundException e) {
szError = e.getMessage();
e.printStackTrace();
logger.error("Can't connect: %s", e);
}
return logger.exit(bConnected);
}
public void disconnect()
{
logger.entry();
try {
db.close();
bConnected = false;
} catch(SQLException e) {
e.printStackTrace();
logger.error("Can't disconnect: %s", e);
}
logger.exit();
}
public boolean isConnected()
{
return bConnected;
}
public String getError()
{
return szError;
}
public ArrayList<HashMap<String,String>> query(String szQuery)
{
logger.entry(szQuery);
ArrayList<HashMap<String,String>> aResults = new ArrayList<HashMap<String,String>>();
int iCols = 0;
try {
Statement stmt = db.createStatement();
logger.info("Query: %s", szQuery);
ResultSet rs = stmt.executeQuery(szQuery);
ResultSetMetaData rsmd = rs.getMetaData();
iCols = rsmd.getColumnCount();
while(rs.next())
{
HashMap<String,String> pv = new HashMap<String,String>();
for(int i = 0; i < iCols; i++)
{
String szCol = rsmd.getColumnLabel(i + 1);
String szVal = rs.getString(i + 1);
pv.put(szCol, szVal);
}
aResults.add(pv);
}
rs.close();
stmt.close();
} catch(SQLException e) {
e.printStackTrace();
szError = e.getMessage();
logger.error("Error executing query: %s", e);
}
return logger.exit(aResults);
}
public boolean update(String szQuery)
{
logger.entry(szQuery);
boolean bResult = false;
try {
Statement stmt = db.createStatement();
logger.info("Query: %s", szQuery);
stmt.executeUpdate(szQuery);
bResult = true;
stmt.close();
} catch(SQLException e) {
e.printStackTrace();
szError = e.getMessage();
bResult = false;
logger.error("Error executing query: %s", e);
}
return logger.exit(bResult);
}
}
The class Task which all the servlet classes are based on, is a simple abstract class:
package it.metmi.mmasgis.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public abstract class Task
{
public abstract void doTask(HttpServletRequest request, HttpServletResponse response);
}
The class which throws NullPointerExceptions it this one, during the invocation of db.disconnect(). This class is called rapidly via AJAX 4 or 5 times from the interface written in JS.
package it.metmi.mmasgis.servlet.params;
import it.metmi.mmasgis.servlet.Task;
import it.metmi.mmasgis.utils.Const;
import it.metmi.mmasgis.utils.DBManager;
import it.metmi.mmasgis.utils.Query;
import it.metmi.mmasgis.utils.Utility;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class ClassType extends Task
{
private DBManager db = null;
private Logger logger = LogManager.getFormatterLogger(ClassType.class.getName());
#Override
public void doTask(HttpServletRequest request, HttpServletResponse response)
{
logger.entry(request, response);
String szCensimento = Utility.getParameter(request, "censimento");
String szCategoria = Utility.getParameter(request, "category");
ArrayList<HashMap<String,String>> aClasses = new ArrayList<HashMap<String,String>>();
PrintWriter out = null;
logger.debug("Census: %s", szCensimento);
logger.debug("Category: %s", szCategoria);
db = new DBManager(szCensimento, Const.DB_USER, Const.DB_PASS);
if(db.connect())
{
String szQuery = String.format(Query.classes, szCategoria, szCategoria);
aClasses = db.query(szQuery);
db.disconnect();
}
try {
out = response.getWriter();
jsonEncode(aClasses, out);
} catch(IOException e) {
e.printStackTrace();
logger.error("Failed to encode JSON: %s", e);
}
logger.exit();
}
private void jsonEncode(ArrayList<HashMap<String,String>> aData, PrintWriter out)
{
HashMap<String,Object> result = new HashMap<String,Object>();
result.put("results", aData);
result.put("success", true);
Gson gson = new GsonBuilder().create();
gson.toJson(result, out);
}
}
If the webapp would use only one database, it could be rewritten as a Singleton, but in this way I have no idea on how to handle different connections for different databases.
How can avoid these exceptions?
The problem was that the connection object was declared as member.
Moving the variable inside the methods resolved.

HttpClient set credentials for Kerberos authentication

I am trying to authenticate with a kerberos/HTTP host. Using Apache HttpClient as my client - and a slightly modified version of this source.
My Kerberos authentication goes perfectly fine, and I wish to know how to set the login credentials programatically. At the moment, the credentials are entered manually through the console, but I want to have it chosen by me at run time. [ As I wish to automate and load test the server with a large number of users, actually. ].
EDIT : Here is a code snippet of the relevant parts :
..
NegotiateSchemeFactory nsf = new NegotiateSchemeFactory();
httpclient.getAuthSchemes().register(AuthPolicy.SPNEGO, nsf);
Credentials use_jaas_creds = new Credentials() {
public String getPassword() {
return null;
}
public Principal getUserPrincipal() {
return null;
}
};
httpclient.getCredentialsProvider().setCredentials(
new AuthScope(null, -1, null),
use_jaas_creds);
HttpUriRequest request = new HttpGet("http://kerberoshost/");
HttpResponse response = httpclient.execute(request);
..
The interface Credentials has two methods - getPassword() and getUserPrincipal(), but from some debugging I did, they don't seem to be invoked at all.
What am I missing here ? What is a cleaner way to statically set the credentials ?
A very similar question had been asked before, but keytabs/login.conf hack is too cumbersome and not a practical option for an automated load test with a large number of user credentials.
Appreciate any help on this.
Because of SPNEGO the snippet code you post (Credentials class stuff setup) is not used by httpclient to authenticate.
You can use a DoAs + a CallBackhandler to pass user & password at runtime.
Then you need a login.conf or whatever the name with this inside:
KrbLogin{
com.sun.security.auth.module.Krb5LoginModule required doNotPrompt=false debug=true useTicketCache=false;
};
You can change the name from "KrbLogin" to the name you like (remember to use the same name in your java code)
and set this with java system properties:
System.setProperty("java.security.auth.login.config", "login.conf");
or with a
-Djava.security.auth.login.config=login.config
Then you need a krb5 config file (usually krb5.ini or krb5.conf with correct configuration inside)
If your workstation (or server) is properly configured for Kerberos this class should works as is (with propper file login.conf and krb5.ini) I used httpclient 4.3.3 and java 1.7 to test it:
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthSchemeProvider;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.impl.auth.SPNegoSchemeFactory;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import javax.security.auth.Subject;
import javax.security.auth.callback.*;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import java.io.IOException;
import java.security.AccessController;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.util.Set;
public class HttpClientKerberosDoAS {
public static void main(String[] args) throws Exception {
System.setProperty("java.security.auth.login.config", "login.conf");
System.setProperty("java.security.krb5.conf", "krb5.conf");
System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
String user = "";
String password = "";
String url = "";
if (args.length == 3) {
user = args[0];
password = args[1];
url = args[2];
HttpClientKerberosDoAS kcd = new HttpClientKerberosDoAS();
System.out.println("Loggin in with user [" + user + "] password [" + password + "] ");
kcd.test(user, password, url);
} else {
System.out.println("run with User Password URL");
}
}
public void test(String user, String password, final String url) {
try {
LoginContext loginCOntext = new LoginContext("KrbLogin", new KerberosCallBackHandler(user, password));
loginCOntext.login();
PrivilegedAction sendAction = new PrivilegedAction() {
#Override
public Object run() {
try {
Subject current = Subject.getSubject(AccessController.getContext());
System.out.println("----------------------------------------");
Set<Principal> principals = current.getPrincipals();
for (Principal next : principals) {
System.out.println("DOAS Principal: " + next.getName());
}
System.out.println("----------------------------------------");
call(url);
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
};
Subject.doAs(loginCOntext.getSubject(), sendAction);
} catch (LoginException le) {
le.printStackTrace();
}
}
private void call(String url) throws IOException {
HttpClient httpclient = getHttpClient();
try {
HttpUriRequest request = new HttpGet(url);
HttpResponse response = httpclient.execute(request);
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println("STATUS >> " + response.getStatusLine());
if (entity != null) {
System.out.println("RESULT >> " + EntityUtils.toString(entity));
}
System.out.println("----------------------------------------");
EntityUtils.consume(entity);
} finally {
httpclient.getConnectionManager().shutdown();
}
}
private HttpClient getHttpClient() {
Credentials use_jaas_creds = new Credentials() {
public String getPassword() {
return null;
}
public Principal getUserPrincipal() {
return null;
}
};
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(new AuthScope(null, -1, null), use_jaas_creds);
Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create().register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory(true)).build();
CloseableHttpClient httpclient = HttpClients.custom().setDefaultAuthSchemeRegistry(authSchemeRegistry).setDefaultCredentialsProvider(credsProvider).build();
return httpclient;
}
class KerberosCallBackHandler implements CallbackHandler {
private final String user;
private final String password;
public KerberosCallBackHandler(String user, String password) {
this.user = user;
this.password = password;
}
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (Callback callback : callbacks) {
if (callback instanceof NameCallback) {
NameCallback nc = (NameCallback) callback;
nc.setName(user);
} else if (callback instanceof PasswordCallback) {
PasswordCallback pc = (PasswordCallback) callback;
pc.setPassword(password.toCharArray());
} else {
throw new UnsupportedCallbackException(callback, "Unknown Callback");
}
}
}
}
}
Note:
you can use:
System.setProperty("sun.security.krb5.debug", "true");
or:
-Dsun.security.krb5.debug=true
to investigate problems.

fineuploader file list empty

I am using fineuploader within a struts system but am having trouble getting the file list in the server code.
My jsp contains the following code:
$("#fine-uploader").fineUploader({
debug: true,
request: {
endpoint: '/NRGI/act_MultiPhotoUpload.do'
},
deleteFile: {
enabled: true,
endpoint: '/uploads'
},
retry: {
enableAuto: true
}
});
with the following div near the bottom of the page:
<div id="fine-uploader"></div>
The action actMultiPhotoUpload points to a class via the struts.config.xml file:
<action path="/act_MultiPhotoUpload" name="FileUploadForm" scope="request" validate="true"
type="com.solarcentury.nrgi.document.action.MultiUploadAction"
input="/D5_PhotoLibrary.jsp">
</action>
The class MultiUploadAction is taken from your UploadReceiver and is as follows:
public class MultiUploadAction extends Action {
static Static_Env_Object seo = new Static_Env_Object();
private String UPLOAD_NOT_ALLOWED = "exe";
private EnvUtils eu;
// JUST FOR TESTING
private static final File UPLOAD_DIR = new File("Test/uploads");
private static File TEMP_DIR = new File("Test/uploadsTemp");
private static String CONTENT_LENGTH = "Content-Length";
private static int SUCCESS_RESPONSE_CODE = 200;
#Override
public ActionForward perform(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
HttpSession session = request.getSession();
String sId = session.getId();
eu = new EnvUtils(seo.get_Env_Name(), this.getClass().getSimpleName());
/* **************************************** */
/* * The code for the session timeout check */
/* **************************************** */
if (session.getAttribute("SESS_User") == null) {
eu.log("NO SESSION", "Session timed out...");
return (mapping.findForward("globaltimeout"));
}
UserObject suo = new UserObj_Util(session).get_SessUser();
WebAlertMessages wam = new WebAlertMessages(request, suo.get_Language_ID());
DemonUtil du = new DemonUtil(seo.get_Env_Name());
// DateUtils dateUtil = new DateUtils();
RequestParser requestParser = null;
boolean isIframe = request.getHeader("X-Requested-With") == null || !request.getHeader("X-Requested-With").equals("XMLHttpRequest");
try
{
// resp.setContentType(isIframe ? "text/html" : "text/plain");
response.setContentType("text/plain");
response.setStatus(SUCCESS_RESPONSE_CODE);
// resp.addHeader("Access-Control-Allow-Origin", "http://192.168.130.118:8080");
// resp.addHeader("Access-Control-Allow-Credentials", "true");
// resp.addHeader("Access-Control-Allow-Origin", "*");
if (ServletFileUpload.isMultipartContent(request))
{
MultipartUploadParser multipartUploadParser = new MultipartUploadParser(request, TEMP_DIR, request.getSession().getServletContext());
requestParser = RequestParser.getInstance(request, multipartUploadParser);
writeFileForMultipartRequest(requestParser);
writeResponse(response.getWriter(), requestParser.generateError() ? "Generated error" : null, isIframe, false, requestParser);
}
else
{
requestParser = RequestParser.getInstance(request, null);
//handle POST delete file request
if (requestParser.getMethod() != null
&& requestParser.getMethod().equalsIgnoreCase("DELETE"))
{
String uuid = requestParser.getUuid();
handleDeleteFileRequest(uuid, response);
}
else
{
writeFileForNonMultipartRequest(request, requestParser);
writeResponse(response.getWriter(), requestParser.generateError() ? "Generated error" : null, isIframe, false, requestParser);
}
}
} catch (Exception e)
{
eu.log("UploadReceiver","Problem handling upload request" + e);
if (e instanceof MultiUploadAction.MergePartsException)
{
writeResponse(response.getWriter(), e.getMessage(), isIframe, true, requestParser);
}
else
{
writeResponse(response.getWriter(), e.getMessage(), isIframe, false, requestParser);
}
}
return (new ActionForward(mapping.getInput()));
}
And I use the MultipartUploadParser, RequestParser from the server java examples on the website.
When I step through the code, how ever many files I select to upload, the file list is always empty. Obviously I am doing something stupid here, but would appreciate any guidance please.
I have seen a similar support question where the asker was having trouble getting the filelist, also using struts, but there wasn't an answer against the question
Added on 14/11/2013
The full code is as follows:
The full listing of MultiUploadAction.java is as follows:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.solarcentury.nrgi.document.action;
/**
*
* #author Roy
*/
import DemonWeb.DmForms.FileUploadForm;
import DemonWeb.DmLogic.DemonUtil;
import DemonWeb.DmLogic.Project;
import DemonWeb.DmSession.Static_Env_Object;
import DemonWeb.DmSession.UserObj_Util;
import DemonWeb.DmSession.UserObject;
import DemonWeb.DmSession.WebAlertMessages;
import DemonWeb.Utils.EnvUtils;
import com.solarcentury.nrgi.document.bean.Document;
import com.solarcentury.nrgi.document.logic.DocumentController;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import java.util.Enumeration;
import java.util.Collections;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.upload.FormFile;
/**
*
* #author ajantham
*/
public class MultiUploadAction extends Action {
static Static_Env_Object seo = new Static_Env_Object();
private String UPLOAD_NOT_ALLOWED = "exe";
private EnvUtils eu;
// JUST FOR TESTING
private static final File UPLOAD_DIR = new File("uploads");
private static File TEMP_DIR = new File("uploadsTemp");
private static String CONTENT_LENGTH = "Content-Length";
private static int SUCCESS_RESPONSE_CODE = 200;
#Override
public ActionForward perform(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
HttpSession session = request.getSession();
String sId = session.getId();
eu = new EnvUtils(seo.get_Env_Name(), this.getClass().getSimpleName());
/* **************************************** */
/* * The code for the session timeout check */
/* **************************************** */
if (session.getAttribute("SESS_User") == null) {
eu.log("NO SESSION", "Session timed out...");
return (mapping.findForward("globaltimeout"));
}
UserObject suo = new UserObj_Util(session).get_SessUser();
WebAlertMessages wam = new WebAlertMessages(request, suo.get_Language_ID());
DemonUtil du = new DemonUtil(seo.get_Env_Name());
// DateUtils dateUtil = new DateUtils();
RequestParser requestParser = null;
boolean isIframe = request.getHeader("X-Requested-With") == null || !request.getHeader("X-Requested-With").equals("XMLHttpRequest");
try
{
// resp.setContentType(isIframe ? "text/html" : "text/plain");
response.setContentType("text/plain");
response.setStatus(SUCCESS_RESPONSE_CODE);
// resp.addHeader("Access-Control-Allow-Origin", "http://192.168.130.118:8080");
// resp.addHeader("Access-Control-Allow-Credentials", "true");
// resp.addHeader("Access-Control-Allow-Origin", "*");
if (ServletFileUpload.isMultipartContent(request))
{
MultipartUploadParser multipartUploadParser = new MultipartUploadParser(request, TEMP_DIR, request.getSession().getServletContext());
requestParser = RequestParser.getInstance(request, multipartUploadParser);
writeFileForMultipartRequest(requestParser);
writeResponse(response.getWriter(), requestParser.generateError() ? "Generated error" : null, isIframe, false, requestParser);
}
else
{
requestParser = RequestParser.getInstance(request, null);
//handle POST delete file request
if (requestParser.getMethod() != null
&& requestParser.getMethod().equalsIgnoreCase("DELETE"))
{
String uuid = requestParser.getUuid();
handleDeleteFileRequest(uuid, response);
}
else
{
writeFileForNonMultipartRequest(request, requestParser);
writeResponse(response.getWriter(), requestParser.generateError() ? "Generated error" : null, isIframe, false, requestParser);
}
}
} catch (Exception e)
{
eu.log("UploadReceiver","Problem handling upload request" + e);
if (e instanceof MultiUploadAction.MergePartsException)
{
writeResponse(response.getWriter(), e.getMessage(), isIframe, true, requestParser);
}
else
{
writeResponse(response.getWriter(), e.getMessage(), isIframe, false, requestParser);
}
}
return (new ActionForward(mapping.getInput()));
}
public void doDelete(HttpServletRequest req, HttpServletResponse resp) throws IOException
{
String uuid = req.getPathInfo().replaceAll("/", "");
handleDeleteFileRequest(uuid, resp);
}
private void handleDeleteFileRequest(String uuid, HttpServletResponse resp) throws IOException
{
FileUtils.deleteDirectory(new File(UPLOAD_DIR, uuid));
if (new File(UPLOAD_DIR, uuid).exists())
{
eu.log("UploadReceiver","couldn't find or delete " + uuid);
}
else
{
eu.log("UploadReceiver","deleted " + uuid);
}
resp.setStatus(SUCCESS_RESPONSE_CODE);
// resp.addHeader("Access-Control-Allow-Origin", "*");
}
private void writeFileForNonMultipartRequest(HttpServletRequest req, RequestParser requestParser) throws Exception
{
File dir = new File(UPLOAD_DIR, requestParser.getUuid());
dir.mkdirs();
String contentLengthHeader = req.getHeader(CONTENT_LENGTH);
long expectedFileSize = Long.parseLong(contentLengthHeader);
if (requestParser.getPartIndex() >= 0)
{
writeFile(req.getInputStream(), new File(dir, requestParser.getUuid() + "_" + String.format("%05d", requestParser.getPartIndex())), null);
if (requestParser.getTotalParts()-1 == requestParser.getPartIndex())
{
File[] parts = getPartitionFiles(dir, requestParser.getUuid());
File outputFile = new File(dir, requestParser.getFilename());
for (File part : parts)
{
mergeFiles(outputFile, part);
}
assertCombinedFileIsVaid(requestParser.getTotalFileSize(), outputFile, requestParser.getUuid());
deletePartitionFiles(dir, requestParser.getUuid());
}
}
else
{
writeFile(req.getInputStream(), new File(dir, requestParser.getFilename()), expectedFileSize);
}
}
private void writeFileForMultipartRequest(RequestParser requestParser) throws Exception
{
File dir = new File(UPLOAD_DIR, requestParser.getUuid());
dir.mkdirs();
if (requestParser.getPartIndex() >= 0)
{
writeFile(requestParser.getUploadItem().getInputStream(), new File(dir, requestParser.getUuid() + "_" + String.format("%05d", requestParser.getPartIndex())), null);
if (requestParser.getTotalParts()-1 == requestParser.getPartIndex())
{
File[] parts = getPartitionFiles(dir, requestParser.getUuid());
File outputFile = new File(dir, requestParser.getOriginalFilename());
for (File part : parts)
{
mergeFiles(outputFile, part);
}
assertCombinedFileIsVaid(requestParser.getTotalFileSize(), outputFile, requestParser.getUuid());
deletePartitionFiles(dir, requestParser.getUuid());
}
}
else
{
writeFile(requestParser.getUploadItem().getInputStream(), new File(dir, requestParser.getFilename()), null);
}
}
private void assertCombinedFileIsVaid(int totalFileSize, File outputFile, String uuid) throws MultiUploadAction.MergePartsException
{
if (totalFileSize != outputFile.length())
{
deletePartitionFiles(UPLOAD_DIR, uuid);
outputFile.delete();
throw new MultiUploadAction.MergePartsException("Incorrect combined file size!");
}
}
private static class PartitionFilesFilter implements FilenameFilter
{
private String filename;
PartitionFilesFilter(String filename)
{
this.filename = filename;
}
#Override
public boolean accept(File file, String s)
{
return s.matches(Pattern.quote(filename) + "_\\d+");
}
}
private static File[] getPartitionFiles(File directory, String filename)
{
File[] files = directory.listFiles(new MultiUploadAction.PartitionFilesFilter(filename));
Arrays.sort(files);
return files;
}
private static void deletePartitionFiles(File directory, String filename)
{
File[] partFiles = getPartitionFiles(directory, filename);
for (File partFile : partFiles)
{
partFile.delete();
}
}
private File mergeFiles(File outputFile, File partFile) throws IOException
{
FileOutputStream fos = new FileOutputStream(outputFile, true);
try
{
FileInputStream fis = new FileInputStream(partFile);
try
{
IOUtils.copy(fis, fos);
}
finally
{
IOUtils.closeQuietly(fis);
}
}
finally
{
IOUtils.closeQuietly(fos);
}
return outputFile;
}
private File writeFile(InputStream in, File out, Long expectedFileSize) throws IOException
{
FileOutputStream fos = null;
try
{
fos = new FileOutputStream(out);
IOUtils.copy(in, fos);
if (expectedFileSize != null)
{
Long bytesWrittenToDisk = out.length();
if (!expectedFileSize.equals(bytesWrittenToDisk))
{
eu.log("UploadReceiver","Expected file {} to be {} bytes; file on disk is {} bytes " + new Object[] { out.getAbsolutePath(), expectedFileSize, 1 });
out.delete();
throw new IOException(String.format("Unexpected file size mismatch. Actual bytes %s. Expected bytes %s.", bytesWrittenToDisk, expectedFileSize));
}
}
return out;
}
catch (Exception e)
{
throw new IOException(e);
}
finally
{
IOUtils.closeQuietly(fos);
}
}
private void writeResponse(PrintWriter writer, String failureReason, boolean isIframe, boolean restartChunking, RequestParser requestParser)
{
if (failureReason == null)
{
// if (isIframe)
// {
// writer.print("{\"success\": true, \"uuid\": \"" + requestParser.getUuid() + "\"}<script src=\"http://192.168.130.118:8080/client/js/iframe.xss.response.js\"></script>");
// }
// else
// {
writer.print("{\"success\": true}");
// }
}
else
{
if (restartChunking)
{
writer.print("{\"error\": \"" + failureReason + "\", \"reset\": true}");
}
else
{
// if (isIframe)
// {
// writer.print("{\"error\": \"" + failureReason + "\", \"uuid\": \"" + requestParser.getUuid() + "\"}<script src=\"http://192.168.130.118:8080/client/js/iframe.xss.response.js\"></script>");
// }
// else
// {
writer.print("{\"error\": \"" + failureReason + "\"}");
// }
}
}
}
private class MergePartsException extends Exception
{
MergePartsException(String message)
{
super(message);
}
}
}
The full source of MultipartUploadParser.java is as follows:
package com.solarcentury.nrgi.document.action;
import DemonWeb.DmSession.Static_Env_Object;
import DemonWeb.Utils.EnvUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.FileCleanerCleanup;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileCleaningTracker;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;
public class MultipartUploadParser
{
// final Logger log = LoggerFactory.getLogger(MultipartUploadParser.class);
static Static_Env_Object seo = new Static_Env_Object();
private EnvUtils eu;
private Map<String, String> params = new HashMap<String, String>();
private List<FileItem> files = new ArrayList<FileItem>();
// fileItemsFactory is a field (even though it's scoped to the constructor) to prevent the
// org.apache.commons.fileupload.servlet.FileCleanerCleanup thread from attempting to delete the
// temp file before while it is still being used.
//
// FileCleanerCleanup uses a java.lang.ref.ReferenceQueue to delete the temp file when the FileItemsFactory marker object is GCed
private DiskFileItemFactory fileItemsFactory;
public MultipartUploadParser(HttpServletRequest request, File repository, ServletContext context) throws Exception
{
this.eu = new EnvUtils(seo.get_Env_Name(), "MultipartUploadParser " + "1.0.0.0");
if (!repository.exists() && !repository.mkdirs())
{
throw new IOException("Unable to mkdirs to " + repository.getAbsolutePath());
}
fileItemsFactory = setupFileItemFactory(repository, context);
ServletFileUpload upload = new ServletFileUpload(fileItemsFactory);
List<FileItem> formFileItems = upload.parseRequest(request);
parseFormFields(formFileItems);
if (files.isEmpty())
{
eu.log("MultipartUploadParser","No files were found when processing the request. Debugging info follows");
writeDebugInfo(request);
throw new FileUploadException("No files were found when processing the request.");
}
else
{
writeDebugInfo(request);
}
}
private DiskFileItemFactory setupFileItemFactory(File repository, ServletContext context)
{
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD);
factory.setRepository(repository);
FileCleaningTracker pTracker = FileCleanerCleanup.getFileCleaningTracker(context);
factory.setFileCleaningTracker(pTracker);
return factory;
}
private void writeDebugInfo(HttpServletRequest request)
{
eu.log("MultipartUploadParser","-- POST HEADERS --");
for (String header : Collections.list((Enumeration<String>) request.getHeaderNames()))
{
eu.log("MultipartUploadParser", header + "header " + request.getHeader(header));
}
eu.log("MultipartUploadParser","-- POST PARAMS --");
for (String key : params.keySet())
{
eu.log("MultipartUploadParser", key + " key " + params.get(key));
}
}
private void parseFormFields(List<FileItem> items) throws UnsupportedEncodingException
{
for (FileItem item : items)
{
if (item.isFormField())
{
String key = item.getFieldName();
String value = item.getString("UTF-8");
if (StringUtils.isNotBlank(key))
{
params.put(key, StringUtils.defaultString(value));
}
}
else
{
files.add(item);
}
}
}
public Map<String, String> getParams()
{
return params;
}
public List<FileItem> getFiles()
{
if (files.isEmpty())
{
throw new RuntimeException("No FileItems exist.");
}
return files;
}
public FileItem getFirstFile()
{
if (files.isEmpty())
{
throw new RuntimeException("No FileItems exist.");
}
return files.iterator().next();
}
}
MultiUploadAction decides that the request isMultipartContent and so calls MultipartUploadParser. This class successfully
checks the directory structure and then uses its method ParseFormFields to buld up a list of files.
However it does not find any files or form fields, and so on line 62 of MultipartUploadParser files.isEmpty() is true,
and so an exception is thrown (line 70)
It doesn't matter how many files I select in the client, the file list is always empty.
Many thanks for your help in this - much appreciated
I know this is very old, but I ran into this same problem. In my implementation I had tried to adapt the example endpoint code into my Spring MVC project. I discovered that the Spring MVC framework was actually calling the same Apache ServletFileUpload.parseRequest BEFORE passing the request to my controller and detecting the multipart, fetching the params, etc. The framework was parsing the multipart request despite whether I was using MutlipartHttpServlet request, or simply HttpServletRequest as my signature for the controller method. When my code in the MultipartUploadParser hit ServletFileUpload.parseRequest again, this time it returned an empty List because they had already been parsed.
The endpoint example code in the git repo for Fine Uploader works as it is, it was just my adaptation with Spring MVC that didn't work.

Categories

Resources