Refactor and expand core functionalities with new modules
Added robust utility modules: Tone generation, image scaling, and sound tone mapping. Developed an encryption domain with new abstractions. Updated and annotated the SQL query class for clarity and functionality. Removed unused `@Config` annotation.
This commit is contained in:
+49
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>de.neitzel.lib</groupId>
|
||||
<artifactId>neitzellib</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>net</artifactId>
|
||||
|
||||
<properties>
|
||||
<!-- Application Properties -->
|
||||
<link.name>${project.artifactId}</link.name>
|
||||
<launcher>${project.artifactId}</launcher>
|
||||
<appName>${project.artifactId}</appName>
|
||||
<jar.filename>${project.artifactId}-${project.version}</jar.filename>
|
||||
|
||||
<!-- Dependency versions -->
|
||||
<javax.mail.version>1.6.2</javax.mail.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.sun.mail</groupId>
|
||||
<artifactId>javax.mail</artifactId>
|
||||
<version>${javax.mail.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>${jar.filename}</finalName>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-pmd-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,128 @@
|
||||
package de.neitzel.net.imap;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents an IMAP account with server configuration, user credentials, and protocol details.
|
||||
* This class provides methods to set or get the account details and overrides methods for string
|
||||
* representation, equality checks, and hashing.
|
||||
*/
|
||||
public class ImapAccount {
|
||||
|
||||
/**
|
||||
* Specifies the server address for the IMAP account.
|
||||
* This typically represents the hostname or IP address
|
||||
* of the mail server that handles IMAP communication.
|
||||
*/
|
||||
protected String server;
|
||||
/**
|
||||
* Retrieves the server address associated with this IMAP*/
|
||||
public String getServer() { return server; }
|
||||
/**
|
||||
* Sets the server address for the IMAP account.
|
||||
*
|
||||
* @param server the server address to be configured for the IMAP account
|
||||
*/
|
||||
public void setServer(String server) { this.server = server; }
|
||||
|
||||
/**
|
||||
* Represents the username or identifier used to authenticate the IMAP account.
|
||||
* This value is associated with the user's credentials required to log in
|
||||
* to the IMAP server.
|
||||
*/
|
||||
protected String user;
|
||||
/**
|
||||
* Retrieves the username associated with this IMAP account.
|
||||
*
|
||||
* @return the username of the IMAP account as a String.
|
||||
*/
|
||||
public String getUser() { return user; }
|
||||
/**
|
||||
* Sets the username associated with the IMAP account.
|
||||
*
|
||||
* @param user The username to be set for this IMAP account.
|
||||
*/
|
||||
public void setUser(String user) { this.user = user; }
|
||||
|
||||
/**
|
||||
* The password associated with the IMAP account.
|
||||
* This is used to authenticate the user when connecting to the IMAP server.
|
||||
*/
|
||||
protected String password;
|
||||
/**
|
||||
* Retrieves the password associated with this IMAP account.
|
||||
*
|
||||
* @return the password of the IMAP account.
|
||||
*/
|
||||
public String getPassword() { return password; }
|
||||
/**
|
||||
* Sets the password for the IMAP account.
|
||||
*
|
||||
* @param password The password to be set for the account.
|
||||
*/
|
||||
public void setPassword(String password) { this.password = password; }
|
||||
|
||||
/**
|
||||
* Specifies the protocol used for the IMAP account, such as "IMAP" or "IMAPS".
|
||||
* This field determines the communication protocol for interacting with the server.
|
||||
*/
|
||||
protected String protocol;
|
||||
/**
|
||||
* Retrieves the protocol used by this IMAP account.
|
||||
*
|
||||
* @return the protocol as a String, which defines the communication method for the IMAP account.
|
||||
*/
|
||||
public String getProtocol() { return protocol; }
|
||||
/**
|
||||
* Sets the protocol used by the IMAP account.
|
||||
* @param protocol the protocol to be used, e.g., "IMAP" or "IMAPS".
|
||||
*/
|
||||
public void setProtocol(String protocol) { this.protocol = protocol; }
|
||||
|
||||
/**
|
||||
* Provides a string representation of the ImapAccount object including its server, user,
|
||||
* a masked password, and protocol information. The password is represented as '########' if it is not empty.
|
||||
*
|
||||
* @return A formatted string that describes the ImapAccount object with its server, user, masked password, and protocol.
|
||||
*/
|
||||
@Override public String toString() {
|
||||
return String.format("ImapAccount(%s, %s, %s, %s",
|
||||
server,
|
||||
user,
|
||||
password.length()==0 ? "''" : "########" ,
|
||||
protocol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the hash code for this instance of the ImapAccount class.
|
||||
* The hash code is based on the values of the server, user, password, and protocol fields.
|
||||
* This ensures that instances with the same field values produce the same hash code.
|
||||
*
|
||||
* @return An integer hash code representing this ImapAccount instance.
|
||||
*/
|
||||
@Override public int hashCode() {
|
||||
return Objects.hash(server, user, password, protocol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this ImapAccount instance with the specified object for equality.
|
||||
* The comparison is based on the equality of all relevant fields: server, user, password, and protocol.
|
||||
*
|
||||
* @param obj the object to compare with this instance
|
||||
* @return true if the specified object is equal to this ImapAccount instance; false otherwise
|
||||
*/
|
||||
@Override public boolean equals(Object obj) {
|
||||
// Check type of argument, includes check of null.
|
||||
if (!(obj instanceof ImapAccount)) return false;
|
||||
|
||||
// Check Reference equals
|
||||
if (this == obj) return true;
|
||||
|
||||
// Check the comparison of all field
|
||||
ImapAccount other = (ImapAccount) obj;
|
||||
return (server == other.server || (server != null && server.equals(other.server))) &&
|
||||
(user == other.user || (user != null && user.equals(other.user))) &&
|
||||
(password == other.password || (password != null && password.equals(other.password))) &&
|
||||
(protocol == other.protocol || (protocol != null && protocol.equals(other.protocol)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
package de.neitzel.net.imap;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.mail.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* The ImapAccountMonitor class is responsible for monitoring an IMAP email account
|
||||
* by maintaining a connection to the server, tracking specific folders, and
|
||||
* listening for new emails. This class allows managing the set of monitored folders,
|
||||
* processing unseen and undeleted messages, and notifying registered listeners when
|
||||
* new messages are received.
|
||||
*/
|
||||
@Slf4j
|
||||
public class ImapAccountMonitor {
|
||||
/**
|
||||
* Represents an instance of an IMAP account, encapsulating details about
|
||||
* server configuration, user credentials, and protocol settings.
|
||||
* This variable is used to connect and authenticate the application's interaction
|
||||
* with an IMAP email server.
|
||||
*/
|
||||
protected ImapAccount account;
|
||||
|
||||
/**
|
||||
* Represents the current session for interaction with an IMAP server.
|
||||
* The session encapsulates the configuration and context required
|
||||
* to establish a connection and perform operations on the IMAP server.
|
||||
* It is initialized and utilized internally within the application.
|
||||
*/
|
||||
protected Session session;
|
||||
|
||||
/**
|
||||
* Represents the mail store associated with the IMAP account.
|
||||
* The store is used to interact with the IMAP server for email retrieval and management.
|
||||
*/
|
||||
protected Store store;
|
||||
|
||||
/**
|
||||
* Represents a collection of folders associated with an IMAP account.
|
||||
* The map's keys are folder names (String), and the values are Folder objects.
|
||||
* This variable is used to store and manage the hierarchy or collection
|
||||
* of email folders for an IMAP account.
|
||||
*/
|
||||
protected Map<String, Folder> folders = new HashMap<String, Folder>();
|
||||
|
||||
/**
|
||||
* Monitors an IMAP account by establishing a connection to the specified mail server
|
||||
* using the provided account credentials and protocol.
|
||||
*
|
||||
* @param account the IMAP account containing details such as server, user, password, and protocol
|
||||
* @throws NoSuchProviderException if the specified mail store protocol is not available
|
||||
* @throws MessagingException if the connection to the mail server fails
|
||||
*/
|
||||
public ImapAccountMonitor(ImapAccount account) throws NoSuchProviderException, MessagingException {
|
||||
log.trace("Constructor ({})", account.toString());
|
||||
this.account = account;
|
||||
|
||||
Properties props = System.getProperties();
|
||||
props.setProperty("mail.store.protocol", account.getProtocol());
|
||||
session = Session.getDefaultInstance(props);
|
||||
try {
|
||||
store = session.getStore("imaps");
|
||||
store.connect(account.server, account.user, account.password);
|
||||
} catch (NoSuchProviderException ex) {
|
||||
log.error("Unable to get imaps Store.", ex);
|
||||
throw ex;
|
||||
} catch (MessagingException ex) {
|
||||
log.error("Unable to connect.", ex);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
log.trace("Constructor done.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the resources associated with the current instance, including
|
||||
* IMAP folders and the store. The method ensures that all folders are
|
||||
* closed properly, followed by the closure of the store.
|
||||
*
|
||||
* Any exceptions encountered during the closure of folders or the store
|
||||
* are caught and logged without interrupting the overall closing process.
|
||||
* This is to ensure that all resources are attempted to be closed even if
|
||||
* an error occurs with one of them.
|
||||
*
|
||||
* The method logs the start and end of the closing process for traceability.
|
||||
*/
|
||||
public void close() {
|
||||
log.trace("close() called.");
|
||||
|
||||
// Close the folders
|
||||
for (Folder folder: folders.values()) {
|
||||
try {
|
||||
folder.close(false);
|
||||
} catch (MessagingException ex) {
|
||||
// Only log the exception.
|
||||
log.warn("Exception when closing folder.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Close the store
|
||||
try {
|
||||
store.close();
|
||||
} catch (MessagingException ex) {
|
||||
// Only log the error.
|
||||
log.warn("Exception when closing the store.", ex);
|
||||
}
|
||||
|
||||
log.trace("close() call ended.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new folder to the IMAP account and opens it in read-write mode.
|
||||
* The folder is added to an internal collection for future access.
|
||||
*
|
||||
* @param name the name of the folder to be added and opened
|
||||
* @throws MessagingException if any error occurs while accessing or opening the folder
|
||||
*/
|
||||
public void addFolder(String name) throws MessagingException {
|
||||
log.trace("addFolder(%s) called.", name);
|
||||
Folder folder = store.getFolder(name);
|
||||
folder.open(Folder.READ_WRITE);
|
||||
folders.put(name, folder);
|
||||
log.trace("addFolder({}) call ended.", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the folder with the specified name from the account's folder list.
|
||||
* If the folder is not found, the method does nothing.
|
||||
* After removing the folder, it attempts to close any associated resources.
|
||||
*
|
||||
* @param name the name of the folder to be removed
|
||||
*/
|
||||
public void removeFolder(String name) {
|
||||
log.trace("removeFolder({}) called.", name);
|
||||
|
||||
// Validate folder is known.
|
||||
if (!folders.containsKey(name)) return;
|
||||
|
||||
Folder folder = folders.get(name);
|
||||
folders.remove(name);
|
||||
try {
|
||||
folder.close(false);
|
||||
} catch (MessagingException ex) {
|
||||
// TODO: Handle exception ...
|
||||
}
|
||||
|
||||
log.trace("removeFolder({}) call ended.", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks all monitored folders for new email messages, processes unseen and undeleted messages,
|
||||
* and raises a NewMailEvent for each new email discovered. The method ensures processed messages
|
||||
* are marked as seen.
|
||||
*
|
||||
* The method iterates through all folders currently being monitored, fetching their messages and
|
||||
* evaluating the state of each. If a message is neither marked as seen nor deleted, it is marked
|
||||
* as seen and a NewMailEvent is raised for it.
|
||||
*
|
||||
* Proper error handling is implemented to log any MessagingException that occurs while processing
|
||||
* the messages of a folder without interrupting the processing of other folders.
|
||||
*
|
||||
* Note: This method relies on external logging (via `log`) and appropriate event handling
|
||||
* via `raiseNewEmailEvent`. The `folders` collection holds the monitored folders required.
|
||||
*
|
||||
* The folder processing stops only in case of irrecoverable exceptions outside this method's scope.
|
||||
*/
|
||||
public void check() {
|
||||
log.trace("check() called.");
|
||||
|
||||
// Loop through all folders that are monitored
|
||||
for (Folder folder: folders.values()) {
|
||||
try {
|
||||
// Loop through all messages.
|
||||
Message[] messages = folder.getMessages();
|
||||
for (Message message: messages) {
|
||||
// Check if message wasn't seen and wasn't deleted
|
||||
if (!message.isSet(Flags.Flag.SEEN) && !message.isSet(Flags.Flag.DELETED)) {
|
||||
// Mark message as seen.
|
||||
message.setFlag(Flags.Flag.SEEN, true);
|
||||
|
||||
// Raise NewMailEvent
|
||||
raiseNewEmailEvent(message);
|
||||
}
|
||||
}
|
||||
} catch (MessagingException ex) {
|
||||
log.error("Exception when reading messages of folder {}.", folder.getName(), ex);
|
||||
// So far no handling of this error except logging it.
|
||||
}
|
||||
}
|
||||
|
||||
log.trace("check() call ended.");
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of listeners that respond to IMAP-related events.
|
||||
* Each listener in this collection can perform specific actions when triggered
|
||||
* by events such as receiving new email notifications.
|
||||
*/
|
||||
private Collection<ImapListener> imapListeners = new ArrayList<ImapListener>();
|
||||
|
||||
/**
|
||||
* Adds an IMAP listener to receive notifications about IMAP-related events such as new email arrivals.
|
||||
*
|
||||
* @param listener the ImapListener instance to be added to the list of listeners
|
||||
*/
|
||||
public void addImapListener(ImapListener listener) {
|
||||
log.trace("addImapListener() called!");
|
||||
imapListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified IMAP listener from the list of active listeners.
|
||||
* If the listener is present, it will be removed; otherwise, no action is taken.
|
||||
*
|
||||
* @param listener The IMAP listener to be removed.
|
||||
*/
|
||||
public void removeImapListener(ImapListener listener) {
|
||||
log.trace("removeImapListener() called!");
|
||||
if (imapListeners.contains(listener)) {
|
||||
log.info("Removing the IMAP listener.");
|
||||
imapListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Raises a new email event and notifies all registered listeners.
|
||||
* The method loops through the listeners and invokes their {@code NewEmailReceived}
|
||||
* method with a newly created {@link NewEmailEvent}.
|
||||
* If a listener marks the event as handled, the remaining listeners will
|
||||
* not be notified.
|
||||
*
|
||||
* @param message The email message that triggered the event. This message
|
||||
* is included in the {@link NewEmailEvent} passed to the listeners.
|
||||
*/
|
||||
protected void raiseNewEmailEvent(Message message) {
|
||||
log.trace("raiseNewEmailEvent() called!");
|
||||
|
||||
// Create the event.
|
||||
NewEmailEvent event = new NewEmailEvent(this, message);
|
||||
|
||||
// Call all listeners.
|
||||
for (ImapListener listener: imapListeners) {
|
||||
log.trace("Calling listener in {} ....", listener.getClass().getName());
|
||||
listener.newEmailReceived(event);
|
||||
|
||||
// Check if the event was handled so no further ImaListeners will be called.
|
||||
if (event.isHandled()) {
|
||||
log.trace("raiseNewEmailEvent(): Breaking out of listener loop because event was handled.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
log.trace("raiseNewEmailEvent() call ended!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package de.neitzel.net.imap;
|
||||
|
||||
/**
|
||||
* Listener interface for receiving notifications about new emails.
|
||||
* Classes interested in processing new emails should implement this interface and
|
||||
* register themselves to receive events via supported mechanisms.
|
||||
*/
|
||||
public interface ImapListener {
|
||||
/**
|
||||
* This method gets invoked when a new email is received. Implementers of this method
|
||||
* handle the processing of new email events triggered by the associated source.
|
||||
*
|
||||
* @param event the NewEmailEvent object that contains information about the received email,
|
||||
* including the email message and its source.
|
||||
*/
|
||||
void newEmailReceived(NewEmailEvent event);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package de.neitzel.net.imap;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.mail.Message;
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
* Event class representing the occurrence of a new email.
|
||||
* It is typically used to encapsulate information about the received email
|
||||
* and provide a means for event listeners to handle the event.
|
||||
*/
|
||||
public class NewEmailEvent extends EventObject {
|
||||
|
||||
/**
|
||||
* Represents the email message associated with the NewEmailEvent.
|
||||
* This field encapsulates the content and metadata of the email
|
||||
* received, allowing event listeners to process the message details.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
protected Message message;
|
||||
|
||||
/**
|
||||
* Indicates whether the event has already been handled or processed.
|
||||
* When true, it signifies that the event has been handled and no further
|
||||
* processing is required. It is used to prevent multiple handling
|
||||
* of the same event.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
protected boolean handled = false;
|
||||
|
||||
/**
|
||||
* Constructs a new NewEmailEvent instance.
|
||||
* This event encapsulates information about a newly received email,
|
||||
* including its associated message and the source of the event.
|
||||
*
|
||||
* @param source the object on which the event initially occurred; typically represents
|
||||
* the source of the email event, such as an email client or server.
|
||||
* @param message the Message object representing the email associated with this event.
|
||||
*/
|
||||
public NewEmailEvent(Object source, Message message) {
|
||||
super(source);
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package de.neitzel.net.mail;
|
||||
|
||||
import javax.mail.BodyPart;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.ContentType;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Utility functions to use with javax.mail.Message instances.
|
||||
*/
|
||||
public class MessageUtils {
|
||||
/**
|
||||
* Gets the text of the email message.
|
||||
* @param message Message to get the text from.
|
||||
* @return Text of the email message.
|
||||
* @throws IOException
|
||||
* @throws MessagingException
|
||||
*/
|
||||
public static String getTextFromMessage(Message message) throws IOException, MessagingException {
|
||||
String result = "";
|
||||
if (message.isMimeType("text/plain")) {
|
||||
result = message.getContent().toString();
|
||||
} else if (message.isMimeType("multipart/*")) {
|
||||
MimeMultipart mimeMultipart = (MimeMultipart) message.getContent();
|
||||
result = getTextFromMimeMultipart(mimeMultipart);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the text of a MimeMultipart.
|
||||
* @param mimeMultipart MimeMultipart to get the text from.
|
||||
* @return Text of the MimeMultipart instance.
|
||||
* @throws IOException
|
||||
* @throws MessagingException
|
||||
*/
|
||||
private static String getTextFromMimeMultipart(
|
||||
MimeMultipart mimeMultipart) throws IOException, MessagingException {
|
||||
|
||||
int count = mimeMultipart.getCount();
|
||||
if (count == 0)
|
||||
throw new MessagingException("Multipart with no body parts not supported.");
|
||||
boolean multipartAlt = new ContentType(mimeMultipart.getContentType()).match("multipart/alternative");
|
||||
if (multipartAlt)
|
||||
// alternatives appear in an order of increasing
|
||||
// faithfulness to the original content. Customize as req'd.
|
||||
return getTextFromBodyPart(mimeMultipart.getBodyPart(count - 1));
|
||||
String result = "";
|
||||
for (int i = 0; i < count; i++) {
|
||||
BodyPart bodyPart = mimeMultipart.getBodyPart(i);
|
||||
result += getTextFromBodyPart(bodyPart);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the text of a BodyPart
|
||||
* @param bodyPart BodyPart to get text from.
|
||||
* @return Text of body part or empty string if not a known type.
|
||||
* @throws IOException
|
||||
* @throws MessagingException
|
||||
*/
|
||||
private static String getTextFromBodyPart(
|
||||
BodyPart bodyPart) throws IOException, MessagingException {
|
||||
|
||||
String result = "";
|
||||
if (bodyPart.isMimeType("text/plain")) {
|
||||
result = (String) bodyPart.getContent();
|
||||
} else if (bodyPart.isMimeType("text/html")) {
|
||||
result = (String) bodyPart.getContent();
|
||||
//String html = (String) bodyPart.getContent();
|
||||
// Not parsing the html right now!
|
||||
// result = org.jsoup.Jsoup.parse(html).text();
|
||||
} else if (bodyPart.getContent() instanceof MimeMultipart){
|
||||
result = getTextFromMimeMultipart((MimeMultipart)bodyPart.getContent());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user