/****************************************************************************** * This program is free software; you can redistribute it and/or modify it * * under the terms version 2 of the GNU General Public License as published * * by the Free Software Foundation. This program is distributed in the hope * * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * * with this program; if not, write to the Free Software Foundation, Inc., * * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * *****************************************************************************/ package org.idempiere.adinterface; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.util.HashMap; import java.util.Map; import java.util.Properties; import java.util.logging.Level; import javax.servlet.http.HttpServletRequest; import org.adempiere.util.ServerContext; import org.compiere.model.MSession; import org.compiere.model.MSysConfig; import org.compiere.model.MUser; import org.compiere.util.CLogger; import org.compiere.util.DB; import org.compiere.util.DisplayType; import org.compiere.util.Env; import org.compiere.util.KeyNamePair; import org.compiere.util.Language; import org.compiere.util.Login; import org.compiere.util.Util; import org.idempiere.adInterface.x10.ADLoginRequest; /** * @author deepak * @author hengsin * */ public class CompiereService { private static final CLogger log = CLogger.getCLogger(CompiereService.class); private int m_AD_Client_ID; private int m_AD_Org_ID; private int m_AD_User_ID; private int m_AD_Role_ID; private int m_M_Warehouse_ID; private String m_locale; private String m_userName; private String m_password; private int m_expiryMinutes; private long m_lastAuthorizationTime; private String m_IPAddress; private static Map csMap = new HashMap(); private static Map ctxMap = new HashMap(); private boolean m_loggedin = false; /** Localized Date format */ public SimpleDateFormat dateFormat = null; /** JDBC Date format */ public SimpleDateFormat dateFormatJDBC = null; /** Localized Timestamp format */ public SimpleDateFormat dateTimeFormat = null; /** JDBC Timestamp format */ public SimpleDateFormat dateTimeFormatJDBC = null; /** Localized Time format */ public SimpleDateFormat timeFormat = null; /** JDBC Time format */ public SimpleDateFormat timeFormatJDBC = null; private Language m_language; public final String dateFormatOnlyForCtx = "yyyy-MM-dd"; private int m_connectCount; /** * * @return AD_Client_ID of current request */ public synchronized int getAD_Client_ID() { return m_AD_Client_ID; } /** * * @return AD_Org_ID of current request */ public synchronized int getAD_Org_ID() { return m_AD_Org_ID; } /** * * @return context of current request */ public synchronized Properties getCtx() { return Env.getCtx(); } /** * default constructor */ public CompiereService() { m_loggedin = false; m_connectCount = 0; } /** * setup request */ public void connect() { CompiereUtil.initWeb(); ServerContext.setCurrentInstance(new Properties()); Env.setContext(getCtx(), Env.LANGUAGE, "en_US" ); m_language = Language.getLanguage("en_US"); dateFormat = DisplayType.getDateFormat(DisplayType.Date, m_language); dateTimeFormat = DisplayType.getDateFormat(DisplayType.DateTime, m_language); timeFormat = DisplayType.getDateFormat(DisplayType.Time, m_language); dateFormatJDBC = DisplayType.getDateFormat_JDBC(); dateTimeFormatJDBC = DisplayType.getTimestampFormat_Default(); timeFormatJDBC = DisplayType.getTimeFormat_Default(); m_connectCount++; } /** * Increase connect count */ public synchronized void connectCacheInstance() { m_connectCount++; } /** * cleanup request */ public synchronized void disconnect() { m_connectCount--; // TODO: create a thread that checks expired connected compiereservices and log them out expungeIfExpire(); } /** * @return Language of current request */ public synchronized Language getLanguage() { return m_language; } /** * @return true if already logged in */ public synchronized boolean isLoggedIn() { return m_loggedin; } /** * Check Login information and set context. * @returns true if login info are OK * @param ctx context * @param AD_User_ID user * @param AD_Role_ID role * @param AD_Client_ID client * @param AD_Org_ID org * @param M_Warehouse_ID warehouse */ private synchronized String checkLogin (Properties ctx, int AD_User_ID, int AD_Role_ID, int AD_Client_ID, int AD_Org_ID, int M_Warehouse_ID) { // Get Login Info String loginInfo = null; // Verify existence of User/Client/Org/Role and User's access to Client & Org StringBuilder sql = new StringBuilder("SELECT u.Name || '@' || c.Name || '.' || o.Name AS Text") .append(" FROM AD_User u, AD_Client c, AD_Org o, AD_Role r") .append(" WHERE u.AD_User_ID = ?") // #1 .append(" AND c.AD_Client_ID = ?") // #2 .append(" AND o.AD_Org_ID = ?") // #3 .append(" AND r.AD_Role_ID = ?") // #4 .append(" AND (o.AD_Client_ID = 0 OR o.AD_Client_ID=c.AD_Client_ID)") .append(" AND ( ") .append(" r.IsAccessAllOrgs='Y'") .append(" OR (r.IsUseUserOrgAccess='N' AND o.AD_Org_ID IN (SELECT AD_Org_ID FROM AD_Role_OrgAccess ra WHERE ra.AD_Role_ID=r.AD_Role_ID AND ra.IsActive='Y'))") .append(" OR (r.IsUseUserOrgAccess='Y' AND o.AD_Org_ID IN (SELECT AD_Org_ID FROM AD_User_OrgAccess ua WHERE ua.AD_User_ID=u.AD_User_ID AND ua.IsActive='Y'))") .append(")"); PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql.toString(), null); pstmt.setInt(1, AD_User_ID); pstmt.setInt(2, AD_Client_ID); pstmt.setInt(3, AD_Org_ID); pstmt.setInt(4, AD_Role_ID); rs = pstmt.executeQuery(); if (rs.next()) loginInfo = rs.getString(1); } catch (SQLException e) { e.printStackTrace(); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } // not verified if (loginInfo == null) return null; // Set Preferences KeyNamePair org = new KeyNamePair(AD_Org_ID, String.valueOf(AD_Org_ID)); KeyNamePair wh = null; if (M_Warehouse_ID > 0) wh = new KeyNamePair(M_Warehouse_ID, String.valueOf(M_Warehouse_ID)); // Timestamp date = null; String printer = null; Login login = new Login(ctx); login.loadPreferences(org, wh, date, printer); // return loginInfo; } // checkLogin /** * * @param AD_User_ID * @param AD_Role_ID * @param AD_Client_ID * @param AD_Org_ID * @param M_Warehouse_ID * @param Lang * @return true if login is successful */ public synchronized boolean login( int AD_User_ID, int AD_Role_ID, int AD_Client_ID, int AD_Org_ID, int M_Warehouse_ID, String Lang ) { m_loggedin = false; String loginInfo = checkLogin (getCtx(), AD_User_ID, AD_Role_ID, AD_Client_ID, AD_Org_ID, M_Warehouse_ID ); if (loginInfo == null) return false; m_AD_Client_ID = AD_Client_ID; m_AD_Org_ID = AD_Org_ID; m_AD_User_ID = AD_User_ID; m_AD_Role_ID = AD_Role_ID; m_M_Warehouse_ID = M_Warehouse_ID; m_locale = Lang; boolean email_login = MSysConfig.getBooleanValue(MSysConfig.USE_EMAIL_FOR_LOGIN, false); MUser user = MUser.get(getCtx(), m_AD_User_ID); if (email_login) m_userName = user.getEMail(); else m_userName = Util.isEmpty(user.getLDAPUser()) ? user.getName() : user.getLDAPUser(); Env.setContext( getCtx(), Env.LANGUAGE, Lang); m_language = Language.getLanguage(Lang); Env.verifyLanguage( getCtx(), m_language ); dateFormat = DisplayType.getDateFormat(DisplayType.Date, m_language); dateTimeFormat = DisplayType.getDateFormat(DisplayType.DateTime, m_language); timeFormat = DisplayType.getDateFormat(DisplayType.Time, m_language); dateFormatJDBC = DisplayType.getDateFormat_JDBC(); dateTimeFormatJDBC = DisplayType.getTimestampFormat_Default(); timeFormatJDBC = DisplayType.getTimeFormat_Default(); // Set Date Timestamp ts = new Timestamp(System.currentTimeMillis()); SimpleDateFormat dateFormat4Timestamp = new SimpleDateFormat( dateFormatOnlyForCtx ); Env.setContext( getCtx(), Env.DATE, dateFormat4Timestamp.format(ts)+" 00:00:00" ); // JDBC format if (log.isLoggable(Level.INFO)) log.info(" #Date = "+ Env.getContextAsDate( getCtx(), Env.DATE)); Env.setContext( getCtx(), Env.M_WAREHOUSE_ID, M_Warehouse_ID ); Env.setContext(getCtx(), Env.LANGUAGE, m_language.getAD_Language()); // Create session MSession session = MSession.get (getCtx()); if (session == null){ log.fine("No Session found"); session = MSession.create (getCtx()); } else { session = new MSession(getCtx(), session.getAD_Session_ID(), null); } session.setWebSession("WebService"); session.setDescription(session.getDescription() + "\nUser Agent: " + getCtx().getProperty("#UserAgent")); session.saveEx(); m_loggedin = true; synchronized (csMap) { //save session in cache String key = getKey(m_AD_Client_ID, m_AD_Org_ID, m_userName, m_AD_Role_ID, m_M_Warehouse_ID, m_locale, m_password, m_IPAddress); if (! csMap.containsKey(key)) { csMap.put(key.toString(), this); Properties savedCache = new Properties(); savedCache.putAll(Env.getCtx()); ctxMap.put(key.toString(), savedCache); if (log.isLoggable(Level.INFO)) log.info("Saving " + this + " in cache"); } } return true; } /** * * @return AD_User_ID of current request */ public synchronized int getAD_User_ID() { return m_AD_User_ID; } /** * * @return AD_Role_ID of current request */ public synchronized int getAD_Role_ID() { return m_AD_Role_ID; } /** * * @return locale code of current request */ public synchronized String getLocale() { return m_locale; } /** * * @return M_Warehouse_ID of current request */ public synchronized int getM_Warehouse_ID() { return m_M_Warehouse_ID; } /** * * @return logged in user name of current request */ public synchronized String getUserName() { return m_userName; } /** * @param pass */ public synchronized void setPassword(String pass) { m_password = pass; } /** * @return logged in password of current request */ public synchronized String getPassword() { return m_password; } /** * @param expiryMinutes */ public synchronized void setExpiryMinutes(int expiryMinutes) { m_expiryMinutes = expiryMinutes; } /** * @return logged in expiry minutes of current request */ public synchronized int getExpiryMinutes() { return m_expiryMinutes; } public synchronized void refreshLastAuthorizationTime() { m_lastAuthorizationTime = System.currentTimeMillis(); } public synchronized void setIPAddress(String remoteAddr) { m_IPAddress = remoteAddr; } public static CompiereService get(HttpServletRequest req, ADLoginRequest loginRequest) { String key = getKey(loginRequest.getClientID(), loginRequest.getOrgID(), loginRequest.getUser(), loginRequest.getRoleID(), loginRequest.getWarehouseID(), loginRequest.getLang(), loginRequest.getPass(), req.getRemoteAddr()); CompiereService l_cs = null; synchronized (csMap) { if (csMap.containsKey(key)) { l_cs = csMap.get(key); if (l_cs != null) { if (l_cs.expungeIfExpire()) { l_cs = null; } else { Properties cachedCtx = ctxMap.get(key); Env.getCtx().putAll(cachedCtx); if (log.isLoggable(Level.INFO)) log.info("Reusing " + l_cs); } } } } return l_cs; } private static String getKey( int aD_Client_ID, int aD_Org_ID, String userName, int aD_Role_ID, int m_Warehouse_ID, String locale, String password, String iPAddress) { StringBuilder key = new StringBuilder() .append(aD_Client_ID).append("|") .append(aD_Org_ID).append("|") .append(userName).append("|") .append(aD_Role_ID).append("|") .append(m_Warehouse_ID).append("|") .append(locale).append("|") .append(password).append("|") .append(iPAddress); return key.toString(); } private synchronized boolean expungeIfExpire() { boolean expired = ( (getExpiryMinutes() <= 0) || (m_lastAuthorizationTime + (getExpiryMinutes() * 60000) <= System.currentTimeMillis()) ); if (m_connectCount==0 && expired) { synchronized (csMap) { String key = getKey(m_AD_Client_ID, m_AD_Org_ID, m_userName, m_AD_Role_ID, m_M_Warehouse_ID, m_locale, m_password, m_IPAddress); if (csMap.containsKey(key)) { csMap.remove(key); } if (ctxMap.containsKey(key)) { Properties cachedCtx = ctxMap.remove(key); Properties currentCtx = ServerContext.getCurrentInstance(); try { ServerContext.setCurrentInstance(cachedCtx); if (log.isLoggable(Level.INFO)) log.info("Closing expired/invalid " + this); Env.logout(); } finally { if (currentCtx == cachedCtx) { ServerContext.dispose(); } else { ServerContext.setCurrentInstance(currentCtx); } } } m_loggedin = false; } } return expired; } }