diff --git a/apps/mailreader/README.txt b/apps/mailreader/README.txt new file mode 100644 index 000000000..cdb3df847 --- /dev/null +++ b/apps/mailreader/README.txt @@ -0,0 +1,15 @@ +README.txt - mailreader-bang + +This application demonstrates switching from the "bang" syntax for invoking +dynamic methods to a general-purpose wild card approach. + +To switch between approaches, edit the struts.xml file to include either the +struts-bang.xml file OR the struts-wildcard.xml. (But not both.) + +When using the -bang application, be sure that the +struts.enable.DynamicMethodInvocation property is set to "true". + +For the -wilcard application. be sure that the +struts.enable.DynamicMethodInvocation property is set to "false". + +---------------------------------------------------------------------------- \ No newline at end of file diff --git a/apps/mailreader/pom.xml b/apps/mailreader/pom.xml new file mode 100644 index 000000000..f4915e2e9 --- /dev/null +++ b/apps/mailreader/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + org.apache.struts + struts2-apps + 2.0-SNAPSHOT + + org.apache.struts + struts2-mailreader + war + Starter Webapp + + + + javax.servlet + servlet-api + 2.4 + provided + + + ${pom.groupId} + struts-mailreader-dao + 1.3.5-SNAPSHOT + + + + + + + + org.mortbay.jetty + maven-jetty6-plugin + + 10 + + + + org.apache.geronimo.specs + geronimo-j2ee_1.4_spec + 1.0 + provided + + + + + + diff --git a/apps/mailreader/src/main/java/mailreader2/ApplicationListener.java b/apps/mailreader/src/main/java/mailreader2/ApplicationListener.java new file mode 100644 index 000000000..c32fb71e0 --- /dev/null +++ b/apps/mailreader/src/main/java/mailreader2/ApplicationListener.java @@ -0,0 +1,231 @@ +/* + * Copyright 1999-2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * $Id: ApplicationListener.java 372087 2006-01-25 03:38:42Z craigmcc $ + */ + +package mailreader2; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.struts.apps.mailreader.dao.impl.memory.MemoryUserDatabase; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import java.io.*; + +/** + *

ServletContextListener that initializes and finalizes the + * persistent storage of User and Subscription information for the Struts + * Demonstration Application, using an in-memory database backed by an XML + * file.

+ *

+ *

IMPLEMENTATION WARNING - If this web application is run + * from a WAR file, or in another environment where reading and writing of the + * web application resource is impossible, the initial contents will be copied + * to a file in the web application temporary directory provided by the + * container. This is for demonstration purposes only - you should + * NOT assume that files written here will survive a restart + * of your servlet container.

+ *

+ *

This class was borrowed from the Shale Mailreader. Changes were:

+ *

+ *

+ *

+ * DEVELOPMENT NOTE - Another approach would be to instantiate the database via Spring. + *

+ */ + +public final class ApplicationListener implements ServletContextListener { + + // ------------------------------------------------------ Manifest Constants + + + /** + *

Appication scope attribute key under which the in-memory version of + * our database is stored.

+ */ + public static final String DATABASE_KEY = "database"; + + + /** + *

Application scope attribute key under which the valid selection + * items for the protocol property is stored.

+ */ + public static final String PROTOCOLS_KEY = "protocols"; + + // ------------------------------------------------------ Instance Variables + + + /** + *

The ServletContext for this web application.

+ */ + private ServletContext context = null; + + + /** + * The {@link MemoryUserDatabase} object we construct and make available. + */ + private MemoryUserDatabase database = null; + + + /** + *

Logging output for this plug in instance.

+ */ + private Log log = LogFactory.getLog(this.getClass()); + + // ------------------------------------------------------------- Properties + + + /** + *

The web application resource path of our persistent database storage + * file.

+ */ + private String pathname = "/WEB-INF/classes/database.xml"; + + /** + *

Return the application resource path to the database.

+ * + * @return application resource path path to the database + */ + public String getPathname() { + return (this.pathname); + } + + /** + *

Set the application resource path to the database.

+ * + * @param pathname to the database + */ + public void setPathname(String pathname) { + this.pathname = pathname; + } + + // ------------------------------------------ ServletContextListener Methods + + + /** + *

Gracefully shut down this database, releasing any resources that + * were allocated at initialization.

+ * + * @param event ServletContextEvent to process + */ + public void contextDestroyed(ServletContextEvent event) { + + log.info("Finalizing memory database plug in"); + + if (database != null) { + try { + database.close(); + } catch (Exception e) { + log.error("Closing memory database", e); + } + } + + context.removeAttribute(DATABASE_KEY); + context.removeAttribute(PROTOCOLS_KEY); + database = null; + context = null; + + } + + + /** + *

Initialize and load our initial database from persistent + * storage.

+ * + * @param event The context initialization event + */ + public void contextInitialized(ServletContextEvent event) { + + log.info("Initializing memory database plug in from '" + + pathname + "'"); + + // Remember our associated ServletContext + this.context = event.getServletContext(); + + // Construct a new database and make it available + database = new MemoryUserDatabase(); + try { + String path = calculatePath(); + if (log.isDebugEnabled()) { + log.debug(" Loading database from '" + path + "'"); + } + database.setPathname(path); + database.open(); + } catch (Exception e) { + log.error("Opening memory database", e); + throw new IllegalStateException("Cannot load database from '" + + pathname + "': " + e); + } + context.setAttribute(DATABASE_KEY, database); + + } + + // -------------------------------------------------------- Private Methods + + + /** + *

Calculate and return an absolute pathname to the XML file to contain + * our persistent storage information.

+ * + * @throws Exception if an input/output error occurs + */ + private String calculatePath() throws Exception { + + // Can we access the database via file I/O? + String path = context.getRealPath(pathname); + if (path != null) { + return (path); + } + + // Does a copy of this file already exist in our temporary directory + File dir = (File) + context.getAttribute("javax.servlet.context.tempdir"); + File file = new File(dir, "struts-example-database.xml"); + if (file.exists()) { + return (file.getAbsolutePath()); + } + + // Copy the static resource to a temporary file and return its path + InputStream is = + context.getResourceAsStream(pathname); + BufferedInputStream bis = new BufferedInputStream(is, 1024); + FileOutputStream os = + new FileOutputStream(file); + BufferedOutputStream bos = new BufferedOutputStream(os, 1024); + byte buffer[] = new byte[1024]; + while (true) { + int n = bis.read(buffer); + if (n <= 0) { + break; + } + bos.write(buffer, 0, n); + } + bos.close(); + bis.close(); + return (file.getAbsolutePath()); + + } + + +} diff --git a/apps/mailreader/src/main/java/mailreader2/AuthenticationInterceptor.java b/apps/mailreader/src/main/java/mailreader2/AuthenticationInterceptor.java new file mode 100644 index 000000000..10cc36823 --- /dev/null +++ b/apps/mailreader/src/main/java/mailreader2/AuthenticationInterceptor.java @@ -0,0 +1,31 @@ +package mailreader2; + +import com.opensymphony.xwork2.interceptor.Interceptor; +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.Action; +import java.util.Map; +import org.apache.struts.apps.mailreader.dao.User; + +public class AuthenticationInterceptor implements Interceptor { + + public void destroy () {} + + public void init() {} + + public String intercept(ActionInvocation actionInvocation) throws Exception { + + Map session = actionInvocation.getInvocationContext().getSession(); + + User user = (User) session.get(Constants.USER_KEY); + + boolean isAuthenticated = (null!=user) && (null!=user.getDatabase()); + + if (!isAuthenticated) { + return Action.LOGIN; + } + else { + return actionInvocation.invoke(); + } + + } +} diff --git a/apps/mailreader/src/main/java/mailreader2/Constants.java b/apps/mailreader/src/main/java/mailreader2/Constants.java new file mode 100644 index 000000000..89d96075a --- /dev/null +++ b/apps/mailreader/src/main/java/mailreader2/Constants.java @@ -0,0 +1,125 @@ +/* + * $Id: Constants.java 360442 2005-12-31 20:10:04Z husted $ + * + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package mailreader2; + +/** + *

Manifest constants for the MailReader application.

+ */ +public final class Constants { + + // --- Tokens ---- + + /** + *

The token representing a "cancel" request.

+ */ + public static final String CANCEL = "cancel"; + + /** + *

The token representing a "create" task.

+ */ + public static final String CREATE = "Create"; + + /** + *

The application scope attribute under which our user database is + * stored.

+ */ + public static final String DATABASE_KEY = "database"; + + /** + *

The token representing a "edit" task.

+ */ + public static final String DELETE = "Delete"; + + /** + *

The token representing a "edit" task.

+ */ + public static final String EDIT = "Edit"; + + /** + *

The package name for this application.

+ */ + public static final String PACKAGE = "org.apache.struts.apps.mailreader"; + + /** + *

The session scope attribute under which the Subscription object + * currently selected by our logged-in User is stored.

+ */ + public static final String SUBSCRIPTION_KEY = "subscription"; + + /** + *

The session scope attribute under which the User object for the + * currently logged in user is stored.

+ */ + public static final String USER_KEY = "user"; + + /** + *

The token representing the "Host" property. + */ + public static final String HOST = "host"; + + + // ---- Error Messages ---- + + /** + *

+ * A static message in case message resource is not loaded. + *

+ */ + public static final String ERROR_MESSAGES_NOT_LOADED = + "ERROR: Message resources not loaded -- check servlet container logs for error messages."; + + /** + *

+ * A static message in case database resource is not loaded. + *

+ */ + public static final String ERROR_DATABASE_NOT_LOADED = + "ERROR: User database not loaded -- check servlet container logs for error messages."; + + /** + *

+ * A standard key from the message resources file, to test if it is available. + *

+ */ + public static final String ERROR_DATABASE_MISSING = "error.database.missing"; + + /** + *

+ * A "magic" username to trigger an ExpiredPasswordException for testing. + *

+ */ + public static final String EXPIRED_PASSWORD_EXCEPTION = "ExpiredPasswordException"; + + /** + *

+ * Name of field to associate with authentification errors. + *

+ */ + public static final String PASSWORD_MISMATCH_FIELD = "password"; + + // ---- Log Messages ---- + + /** + *

Message to log if saving a user fails.

+ */ + public static final String LOG_DATABASE_SAVE_ERROR = + " Unexpected error when saving User: "; + + +} diff --git a/apps/mailreader/src/main/java/mailreader2/Logoff.java b/apps/mailreader/src/main/java/mailreader2/Logoff.java new file mode 100644 index 000000000..4cbafa55a --- /dev/null +++ b/apps/mailreader/src/main/java/mailreader2/Logoff.java @@ -0,0 +1,32 @@ +/* + * $Id: LogonAction.java 360442 2005-12-31 20:10:04Z husted $ + * + * Copyright 2000-2004 Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package mailreader2; + +/** + *

Log user out of the current session.

+ */ +public class Logoff extends MailreaderSupport { + + public String execute() { + + setUser(null); + + return SUCCESS; + } +} diff --git a/apps/mailreader/src/main/java/mailreader2/Logon-validation.xml b/apps/mailreader/src/main/java/mailreader2/Logon-validation.xml new file mode 100644 index 000000000..4a04c7629 --- /dev/null +++ b/apps/mailreader/src/main/java/mailreader2/Logon-validation.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/apps/mailreader/src/main/java/mailreader2/Logon.java b/apps/mailreader/src/main/java/mailreader2/Logon.java new file mode 100644 index 000000000..0c8fa735e --- /dev/null +++ b/apps/mailreader/src/main/java/mailreader2/Logon.java @@ -0,0 +1,45 @@ +/* + * $Id: LogonAction.java 360442 2005-12-31 20:10:04Z husted $ + * + * Copyright 2000-2004 Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package mailreader2; + +import org.apache.struts.apps.mailreader.dao.User; +import org.apache.struts.apps.mailreader.dao.ExpiredPasswordException; + +/** + *

Validate a user logon.

+ */ +public final class Logon extends MailreaderSupport { + + public String execute() throws ExpiredPasswordException { + + User user = findUser(getUsername(), getPassword()); + + if (user != null) { + setUser(user); + } + + if (hasErrors()) { + return INPUT; + } + + return SUCCESS; + + } + +} diff --git a/apps/mailreader/src/main/java/mailreader2/MailreaderSupport.java b/apps/mailreader/src/main/java/mailreader2/MailreaderSupport.java new file mode 100644 index 000000000..71e971c04 --- /dev/null +++ b/apps/mailreader/src/main/java/mailreader2/MailreaderSupport.java @@ -0,0 +1,559 @@ +/* + * $Id: BaseAction.java 360442 2005-12-31 20:10:04Z husted $ + * + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package mailreader2; + +import com.opensymphony.util.BeanUtils; +import org.apache.struts2.interceptor.ApplicationAware; +import org.apache.struts2.interceptor.SessionAware; +import com.opensymphony.xwork2.ActionSupport; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.struts.apps.mailreader.dao.ExpiredPasswordException; +import org.apache.struts.apps.mailreader.dao.Subscription; +import org.apache.struts.apps.mailreader.dao.User; +import org.apache.struts.apps.mailreader.dao.UserDatabase; +import org.apache.struts.apps.mailreader.dao.impl.memory.MemorySubscription; +import org.apache.struts.apps.mailreader.dao.impl.memory.MemoryUser; + +import java.util.Map; + +/** + *

Base Action for MailreaderSupport application.

+ *

+ *

Note that this class does NOT implement model driven because of the way + * the pre-existing model is designed. The MailReader DAO includes immutable + * fields that can only be set on construction, and some objects do not have a + * default construction. One approach would be to mirror all the DAO + * properties on the Actions. As an alternative, this implementations uses the + * DAO properties where possible, and uses local Action properties only as + * needed. To create new objects, a blank temporary object is constructed, and + * the page uses a mix of local Action properties and DAO properties. When the + * new object is to be saved, the local Action properties are used to create + * the object using the DAO factory methods, the input values are copied from + * the temporary object, and the new object is saved. It's kludge, but it + * avoids creating unnecessary local properties. Pick your poison.

+ */ +public class MailreaderSupport extends ActionSupport + implements SessionAware, ApplicationAware { + + /** + * Return CANCEL so apropriate result can be selected. + * @return "cancel" so apropriate result can be selected. + */ + public String cancel() { + return Constants.CANCEL; + } + + + // ---- ApplicationAware ---- + + /** + *

Field to store application context or its proxy.

+ *

+ *

The application context lasts for the life of the application. A + * reference to the database is stored in the application context at + * startup.

+ */ + private Map application; + + /** + *

Store a new application context.

+ * + * @param value A Map representing application state + */ + public void setApplication(Map value) { + application = value; + } + + /** + *

Provide application context.

+ */ + public Map getApplication() { + return application; + } + + // ---- SessionAware ---- + + /** + *

Field to store session context, or its proxy.

+ */ + private Map session; + + /** + *

Store a new session context.

+ * + * @param value A Map representing session state + */ + public void setSession(Map value) { + session = value; + } + + /** + *

Provide session context.

+ * + * @return session context + */ + public Map getSession() { + return session; + } + + // ---- Task property (utilized by UI) ---- + + /** + *

Field to store workflow task.

+ *

+ *

The Task is used to track the state of the CRUD workflows. It can be + * set to Constant.CREATE, Constant.EDIT, or Constant.DELETE as + * needed.

+ */ + private String task = null; + + + /** + *

Provide worklow task.

+ * + * @return Returns the task. + */ + public String getTask() { + return task; + } + + /** + *

Store new workflow task.

+ * + * @param value The task to set. + */ + public void setTask(String value) { + task = value; + } + + // ---- Token property (utilized by UI) ---- + + /** + *

Field to store double-submit guard.

+ */ + private String token = null; + + + /** + *

Provide Token.

+ * + * @return Returns the token. + */ + public String getToken() { + return token; + } + + /** + *

Store new Token.

+ * + * @param value The token to set. + */ + public void setToken(String value) { + token = value; + } + + + // ---- Host property ---- + + /** + *

Field to store Subscription host.

+ *

+ *

The host is an immutable property of the Subscrtion DAP object, so + * we need to store it locally until we are ready to create the + * Subscription.

+ */ + private String host; + + /** + *

Provide tSubscription host.

+ * + * @return host property + */ + public String getHost() { + return host; + } + + /** + *

Store new Subscription host.

+ * + * @param value + */ + public void setHost(String value) { + host = value; + } + + // ---- Password property ---- + + /** + *

Field to store User password property.

+ *

+ *

The User DAO object password proerty is immutable, so we store it + * locally until we are ready to create the object.

+ */ + private String password = null; + + + /** + *

Provide User password

+ * + * @return Returns the password. + */ + public String getPassword() { + return password; + } + + /** + *

Store new User Password

+ * + * @param value The password to set. + */ + public void setPassword(String value) { + password = value; + } + + // ---- Password2 property (confirmation) ---- + + /** + *

Field to store the User password confirmation.

+ *

+ *

When a User object is created, we ask the client to enter the + * password twice, to help ensure the password is being typed + * correctly.

+ */ + private String password2 = null; + + + /** + *

Provide the User password confirmation.

+ * + * @return Returns the confirmationpassword. + */ + public String getPassword2() { + return password2; + } + + /** + *

Store a new User password confirmation.

+ * + * @param value The confirmation password to set. + */ + public void setPassword2(String value) { + password2 = value; + } + + // ---- Username property ---- + + /** + *

Field to store User username.

+ *

+ *

The User DAO object password proerty is immutable, so we store it + * locally until we are ready to create the object.

+ */ + private String username = null; + + + /** + *

Provide User username.

+ * + * @return Returns the User username. + */ + public String getUsername() { + return username; + } + + /** + *

Store new User username

+ * + * @param value The username to set. + */ + public void setUsername(String value) { + username = value; + } + + // ---- Database property ---- + + /** + *

Provide reference to UserDatabase, or null if the database is not + * available.

+ * + * @return a reference to the UserDatabase or null if the database is not + * available + */ + public UserDatabase getDatabase() { + Object db = getApplication().get(Constants.DATABASE_KEY); + if (db == null) { + this.addActionError(getText("error.database.missing")); + } + return (UserDatabase) db; + } + + /** + *

Store a new reference to UserDatabase

+ * + * @param database + */ + public void setDatabase(UserDatabase database) { + getApplication().put(Constants.DATABASE_KEY, database); + } + + // ---- User property ---- + + /** + *

Provide reference to User object for authenticated user.

+ * + * @return User object for authenticated user. + */ + public User getUser() { + return (User) getSession().get(Constants.USER_KEY); + } + + /** + *

Store new reference to User Object.

+ * + * @param user User object for authenticated user + */ + public void setUser(User user) { + getSession().put(Constants.USER_KEY, user); + } + + /** + *

Obtain User object from database, or return null if the credentials + * are not found or invalid.

+ * + * @param username User username + * @param password User password + * @return User object or null if not found + * @throws ExpiredPasswordException + */ + public User findUser(String username, String password) + throws ExpiredPasswordException { + // FIXME: Stupid testing hack to compensate for inadequate DAO layer + if (Constants.EXPIRED_PASSWORD_EXCEPTION.equals(username)) { + throw new ExpiredPasswordException(Constants.EXPIRED_PASSWORD_EXCEPTION); + } + + User user = getDatabase().findUser(username); + if ((user != null) && !user.getPassword().equals(password)) { + user = null; + } + if (user == null) { + this.addFieldError(Constants.PASSWORD_MISMATCH_FIELD, + getText("error.password.mismatch")); + } + return user; + } + + /** + *

Log instance for this application.

+ */ + protected Log log = LogFactory.getLog(Constants.PACKAGE); + + /** + *

Persist the User object, including subscriptions, to the database. + *

+ * + * @throws java.lang.Exception on database error + */ + public void saveUser() throws Exception { + try { + getDatabase().save(); + } catch (Exception e) { + String message = Constants.LOG_DATABASE_SAVE_ERROR + getUser() + .getUsername(); + log.error(message, e); + throw new Exception(message, e); + } + } + + public void createInputUser() { + User user = new MemoryUser(null, null); + setUser(user); + } + + /** + *

Verify input for creating a new user, create the user, and process + * the login.

+ * + * @return A new User and empty Errors if create succeeds, or null and + * Errors if create fails + */ + public User createUser(String username, String password) { + + UserDatabase database = getDatabase(); + User user; + + try { + user = database.findUser(username); + } + + catch (ExpiredPasswordException e) { + user = getUser(); // Just so that it is not null + } + + if (user != null) { + this.addFieldError("username", "error.username.unique"); + return null; + } + + return database.createUser(username); + } + + // Since user.username is immutable, we have to use some local properties + + /** + *

Use the current User object to create a new User object, and make + * the new User object the authenticated user.

+ *

+ *

The "current" User object is usually a temporary object being used + * to capture input.

+ * + * @param _username User username + * @param _password User password + */ + public void copyUser(String _username, String _password) { + User input = getUser(); + input.setPassword(_password); + User user = createUser(_username, _password); + if (null != user) { + BeanUtils.setValues(user, input, null); + setUser(user); + } + } + + // ---- Subscription property ---- + + /** + *

Obtain the cached Subscription object, if any.

+ * + * @return Cached Subscription object or null + */ + public Subscription getSubscription() { + return (Subscription) getSession().get(Constants.SUBSCRIPTION_KEY); + } + + /** + *

Store new User Subscription.

+ * + * @param subscription + */ + public void setSubscription(Subscription subscription) { + getSession().put(Constants.SUBSCRIPTION_KEY, subscription); + } + + /** + *

Obtain User Subscription object for the given host, or return null + * if not found.

+ * + *

It would be possible for this code to throw a NullPointerException, + * but the ExceptionHandler in the xwork.xml will catch that for us.

+ * + * @return The matching Subscription or null + */ + public Subscription findSubscription(String host) { + Subscription subscription; + subscription = getUser().findSubscription(host); + return subscription; + } + + /** + *

Obtain uSER Subscription for the local Host property.

+ *

+ *

Usually, the host property will be set from the client request, + * because it was embedded in a link to the Subcription action. + * + * @return Subscription or null if not found + */ + public Subscription findSubscription() { + return findSubscription(getHost()); + } + + /** + *

Provide a "temporary" User Subscription object that can be used to + * capture input values.

+ */ + public void createInputSubscription() { + Subscription sub = new MemorySubscription(getUser(), null); + setSubscription(sub); + setHost(sub.getHost()); + } + + /** + *

Provide new User Subscription object for the given host, or null if + * the host is not unique.

+ * + * @param host + * @return New User Subscription object or null + */ + public Subscription createSubscription(String host) { + + Subscription sub; + + sub = findSubscription(host); + + if (null != sub) { + // FIXME - localization - "error.host.unique") + addFieldError(Constants.HOST,"That hostname is already defined"); + return null; + } + + return getUser().createSubscription(host); + } + + /** + *

Create a new Subscription from the current Subscription object, + * making the new Subscription the current Subscription.

+ *

+ *

Usually, the "current" Subscription is a temporary object being used + * to capture input values.

+ * + * @param host + */ + public void copySubscription(String host) { + Subscription input = getSubscription(); + Subscription sub = createSubscription(host); + if (null != sub) { + BeanUtils.setValues(sub, input, null); + setSubscription(sub); + setHost(sub.getHost()); + } + } + + /** + *

Delete the current Subscription object from the database.

+ */ + public void removeSubscription() { + getUser().removeSubscription(getSubscription()); + getSession().remove(Constants.SUBSCRIPTION_KEY); + } + + /** + *

Provide MailServer Host for current User Subscription.

+ * + * @return MailServer Host for current User Subscription + */ + public String getSubscriptionHost() { + Subscription sub = getSubscription(); + if (null == sub) { + return null; + } + return sub.getHost(); + } + +} diff --git a/apps/mailreader/src/main/java/mailreader2/MailreaderSupport.properties b/apps/mailreader/src/main/java/mailreader2/MailreaderSupport.properties new file mode 100644 index 000000000..df33d47cc --- /dev/null +++ b/apps/mailreader/src/main/java/mailreader2/MailreaderSupport.properties @@ -0,0 +1,93 @@ +button.cancel=Cancel +button.confirm=Confirm +button.doSubmit=DO_SUBMIT +button.doReset=DO_RESULT +button.doCancel=org.apache.struts.taglib.html.CANCEL +button.reset=Reset +button.save=Save +change.message=Your password has expired. Please ask the system administrator to change it. +change.try=Try Again +change.title=Password Has Expired +database.load=Cannot load database from {0} +error.database.missing=User database is missing, cannot validate logon credentials +error.fromAddress.format=Invalid format for From Address +error.fromAddress.required=From Address is required +error.fullName.required=Full Name is required +error.host.required=Mail Server is required +error.noSubscription=No Subscription bean in user session +error.password.expired=Your password has expired for username {0} +error.password.required=Password is required +error.password2.required=Confirmation password is required +error.password.match=Password and confirmation password must match +error.password.mismatch=Invalid username and/or password, please try again +error.replyToAddress.format=Invalid format for Reply To Address +struts.messages.invalid.token=Cannot submit this form out of order +error.type.invalid=Server Type must be 'imap' or 'pop3' +error.type.required=Server Type is required +error.username.required=Username is required +error.username.unique=That username is already in use - please select another +errors.footer=
+errors.header=

Validation Error

You must correct the following error(s) before proceeding:


+errors.header=

\u5165\u529b\u30c1\u30a7\u30c3\u30af\u30a8\u30e9\u30fc

\u4ee5\u4e0b\u306e\u30a8\u30e9\u30fc\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044:


+errors.header=

\u041e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438 \u0437\u0430\u043d\u0435\u0441\u0435\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445

\u0412\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u043d\u0438\u0436\u0435 \u043e\u0448\u0438\u0431\u043a\u0438: