/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2014 Servoy BV This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ package com.servoy.j2db.server.headlessclient; import java.net.MalformedURLException; import java.net.URL; import java.rmi.RemoteException; import java.text.MessageFormat; import java.util.Enumeration; import java.util.EventObject; import java.util.HashMap; import java.util.Locale; import java.util.MissingResourceException; import java.util.Properties; import java.util.ResourceBundle; import java.util.TimeZone; import javax.swing.Action; import javax.swing.ImageIcon; import com.servoy.j2db.ApplicationException; import com.servoy.j2db.ClientState; import com.servoy.j2db.IApplication; import com.servoy.j2db.IBeanManager; import com.servoy.j2db.ILAFManager; import com.servoy.j2db.IModeManager; import com.servoy.j2db.J2DBGlobals; import com.servoy.j2db.Messages; import com.servoy.j2db.ModeManager; import com.servoy.j2db.cmd.ICmd; import com.servoy.j2db.cmd.ICmdManager; import com.servoy.j2db.dataprocessing.ClientInfo; import com.servoy.j2db.dataprocessing.FoundSetManager; import com.servoy.j2db.persistence.Solution; import com.servoy.j2db.persistence.SolutionMetaData; import com.servoy.j2db.plugins.ClientPluginAccessProvider; import com.servoy.j2db.plugins.IClientPluginAccess; import com.servoy.j2db.plugins.PluginManager; import com.servoy.j2db.scripting.IExecutingEnviroment; import com.servoy.j2db.scripting.ScriptEngine; import com.servoy.j2db.scripting.StartupArguments; import com.servoy.j2db.server.shared.ApplicationServerRegistry; import com.servoy.j2db.server.shared.WebCredentials; import com.servoy.j2db.util.Debug; import com.servoy.j2db.util.ServoyException; import com.servoy.j2db.util.Utils; /** * @author jcompagner * * @since 8.0 * */ public abstract class AbstractApplication extends ClientState implements IApplication { private final HashMap<Locale, Properties> messages = new HashMap<Locale, Properties>(); private transient ResourceBundle localeJarMessages; protected Locale locale; protected TimeZone timeZone; private transient ICmdManager cmdManager; protected final WebCredentials credentials; private transient IBeanManager beanManager; public AbstractApplication(WebCredentials credentials) { super(); this.credentials = credentials; } /* * (non-Javadoc) * * @see com.servoy.j2db.IApplication#getOSName() */ public String getClientOSName() { return System.getProperty("os.name"); //$NON-NLS-1$ } public int getClientPlatform() { // unknown client platform, overridden in WebClient return Utils.PLATFORM_OTHER; } @Override public boolean isRunningRemote() { return false; } @Override public URL getServerURL() { try { return new URL("http://localhost:" + ApplicationServerRegistry.get().getWebServerPort()); //$NON-NLS-1$ } catch (MalformedURLException e) { Debug.error(e); return null; } } public void output(Object msg, int level) { if (level == DEBUG) { Debug.debug(msg); } else if (level == WARNING) { Debug.warn(msg); } else if (level == ERROR) { Debug.error(msg); } else if (level == FATAL) { Debug.fatal(msg); } else { Debug.log(msg); } } @Override public void blockGUI(String reason) { } @Override public void releaseGUI() { } @Override protected void bindUserClient() { //not needed in headless } @Override protected void unBindUserClient() throws Exception { //not needed in headless } public void reportWarningInStatus(String s) { reportWarning(s); } public void reportInfo(String message) { Debug.log(message); } @Override protected IModeManager createModeManager() { return new ModeManager(this); } @Override protected IExecutingEnviroment createScriptEngine() { return new ScriptEngine(this); } @Override protected void checkForActiveTransactions(boolean force) { if (foundSetManager != null) { foundSetManager.rollbackTransaction(true, false, true); } } @Override public void showDefaultLogin() throws ServoyException { if (credentials.getUserName() != null && credentials.getPassword() != null) { authenticate(null, null, new Object[] { credentials.getUserName(), credentials.getPassword() }); } if (getClientInfo().getUserUid() == null) { shutDown(true); throw new ApplicationException(ServoyException.INCORRECT_LOGIN); } } @Override public void logout(Object[] solution_to_open_args) { if (getClientInfo().getUserUid() != null) { if (getSolution() != null && getSolution().requireAuthentication()) { if (closeSolution(false, solution_to_open_args)) // don't shutdown if already closing; wait for the first closeSolution to finish { if (!isClosing) { shutDown(false);//no way to enter username password so shutdown } else { credentials.clear(); getClientInfo().clearUserInfo(); } } } else { credentials.clear(); getClientInfo().clearUserInfo(); } } } public IBeanManager getBeanManager() { if (beanManager == null) { beanManager = ApplicationServerRegistry.get().getBeanManager(); } return beanManager; } @Override protected void createPluginManager() { pluginManager = ApplicationServerRegistry.get().getPluginManager().createEfficientCopy(this); pluginManager.init(); ((PluginManager)pluginManager).initClientPlugins(this, (IClientPluginAccess)(pluginAccess = createClientPluginAccess())); ((FoundSetManager)getFoundSetManager()).setColumnManangers(pluginManager.getColumnValidatorManager(), pluginManager.getColumnConverterManager(), pluginManager.getUIConverterManager()); } protected IClientPluginAccess createClientPluginAccess() { return new ClientPluginAccessProvider(this); } public ICmdManager getCmdManager() { if (cmdManager == null) { cmdManager = new ICmdManager() { public void executeRegisteredAction(String name) { } public void registerAction(String name, Action a) { } public Action getRegisteredAction(String name) { return null; } public void executeCmd(ICmd c, EventObject ie) { } public void init() { } public void flushCachedItems() { } }; } return cmdManager; } @Override public void refreshI18NMessages() { messages.clear(); } public void setI18NMessagesFilter(String columnname, String[] value) { Properties properties = new Properties(); Messages.loadMessagesFromDatabaseInternal(null, getClientInfo().getClientId(), getSettings(), getDataServer(), getRepository(), properties, locale, Messages.ALL_LOCALES, null, null, columnname, value, getFoundSetManager()); Solution solution = getSolution(); Messages.loadMessagesFromDatabaseInternal(solution != null ? solution.getI18nDataSource() : null, getClientInfo().getClientId(), getSettings(), getDataServer(), getRepository(), properties, locale, Messages.ALL_LOCALES, null, null, columnname, value, getFoundSetManager()); synchronized (messages) { messages.put(locale, properties); } } public ResourceBundle getResourceBundle(Locale lc) { final Locale loc = lc != null ? lc : locale != null ? locale : Locale.getDefault(); final ResourceBundle jarMessages = ResourceBundle.getBundle(Messages.BUNDLE_NAME, loc); final Properties msg = getMessages(loc); return new ResourceBundle() { @Override protected Object handleGetObject(String key) { return getI18NMessage(key, null, msg, jarMessages, loc); } @Override public Locale getLocale() { return loc; } @Override public Enumeration<String> getKeys() { return new Enumeration<String>() { private Enumeration< ? > solutionKeys = msg.keys(); private final Enumeration< ? > jarKeys = jarMessages.getKeys(); public String nextElement() { if (solutionKeys != null) return solutionKeys.nextElement().toString(); else return jarKeys.nextElement().toString(); } public boolean hasMoreElements() { if (solutionKeys != null && solutionKeys.hasMoreElements()) { return true; } solutionKeys = null; return jarKeys.hasMoreElements(); } }; } }; } public String getI18NMessage(String key, Object[] args) { if (key == null || key.length() == 0) return key; Properties properties = getMessages(getLocale()); return getI18NMessage(key, args, properties, localeJarMessages, getLocale()); } public String getI18NMessage(String key) { if (key == null || key.length() == 0) return key; Properties properties = getMessages(getLocale()); return getI18NMessage(key, null, properties, localeJarMessages, getLocale()); } public void setI18NMessage(String key, String value) { if (key != null) { Properties properties = getMessages(getLocale()); if (value == null) { properties.remove(key); refreshI18NMessages(); } else { properties.setProperty(key, value); } } } private static String getI18NMessage(String key, Object[] args, Properties msg, ResourceBundle jar, Locale loc) { String realKey = key; if (realKey.startsWith("i18n:")) //$NON-NLS-1$ { realKey = realKey.substring(5); } String message = null; try { message = msg.getProperty(realKey); if (message == null && jar != null) { try { message = jar.getString(realKey); } catch (Exception e) { } } if (message != null) { if (args == null || args.length == 0) { return message; } else { message = Utils.stringReplace(message, "'", "''"); //$NON-NLS-1$ //$NON-NLS-2$ return getFormattedText(message, loc, args); } } return '!' + realKey + '!'; } catch (MissingResourceException e) { return '!' + realKey + '!'; } catch (Exception e) { return '!' + realKey + "!,txt:" + message + ", error:" + e.getMessage(); //$NON-NLS-1$ //$NON-NLS-2$ } } private static String getFormattedText(String message, Locale locale, Object[] args) { MessageFormat mf = new MessageFormat(message); mf.setLocale(locale); return mf.format(args); } private Properties getMessages(Locale loc) { Properties properties = null; synchronized (messages) { properties = messages.get(loc); if (properties == null && getClientInfo() != null) { properties = new Properties(); Messages.invalidConnection = false; Messages.loadMessagesFromDatabaseInternal(null, ApplicationServerRegistry.get().getClientId(), getSettings(), getDataServer(), getRepository(), properties, loc, getFoundSetManager()); if (getSolution() != null) //must be sure that solution is loaded, app might retrieve system messages, before solution loaded! { Messages.loadMessagesFromDatabaseInternal(getSolution().getI18nDataSource(), ApplicationServerRegistry.get().getClientId(), getSettings(), getDataServer(), getRepository(), properties, loc, getFoundSetManager()); messages.put(loc, properties); } } // also test here for the local jar message if (localeJarMessages == null && loc.equals(getLocale())) { localeJarMessages = ResourceBundle.getBundle(Messages.BUNDLE_NAME, loc); } } return properties == null ? new Properties() : properties; } /* * @see IServiceProvider#getI18NMessageIfPrefixed(String,Object[]) */ public String getI18NMessageIfPrefixed(String key) { if (key != null && key.startsWith("i18n:")) //$NON-NLS-1$ { return getI18NMessage(key.substring(5), null); } return key; } public synchronized void setLocale(Locale l) { if (locale != null && locale.equals(l)) return; Locale old = locale; locale = l; localeJarMessages = null; J2DBGlobals.firePropertyChange(this, "locale", old, locale); //$NON-NLS-1$ } public Locale getLocale() { return locale == null ? Locale.getDefault() : locale; } public TimeZone getTimeZone() { return timeZone == null ? TimeZone.getDefault() : timeZone; } @Override public synchronized void setTimeZone(TimeZone zone) { if (timeZone != null && timeZone.equals(zone)) return; TimeZone old = timeZone; timeZone = zone; J2DBGlobals.firePropertyChange(this, "timeZone", old, timeZone); //$NON-NLS-1$ ClientInfo clientInfo = getClientInfo(); clientInfo.setTimeZone(timeZone); try { getClientHost().pushClientInfo(clientInfo.getClientId(), clientInfo); } catch (RemoteException e) { Debug.error(e); } } public ILAFManager getLAFManager() { return null; } @Override public boolean saveSolution() { return true;//not needed here } public void updateUI(int time) { // no use for session/webclients/headless clients } @Override protected void saveSettings() { //do nothing } @Override protected SolutionMetaData showSolutionSelection(SolutionMetaData[] solutions) { return null; } @Override public void activateSolutionMethod(String globalMethodName, StartupArguments argumentsScope) { //not needed cannot push to client } public void setStatusProgress(int progress) { } @Override public void showSolutionLoading(boolean loading) { } public void setStatusText(String text, String tooltip) { } public void setTitle(String title) { } public ImageIcon loadImage(String name) { return null; } }