Showing posts with label Java Code. Show all posts
Showing posts with label Java Code. Show all posts

AI Workflow Orchestrator — Build Multi-LLM Workflows with Spring Boot

AI Workflow Orchestrator — Build Multi-LLM Workflows with Spring Boot

AI Workflow Orchestrator — Build Multi-LLM Workflows with Spring Boot

A lightweight, Spring Boot–friendly plugin framework to orchestrate complex AI workflows — integrating multiple LLMs, local tools (@AiTool), and MCP services with zero boilerplate.

By Ravinderjeet Singh Nagpal
LLMs OpenAI · Anthropic · Ollama Local Tools @AiTool-annotated functions MCP Services via Clients HTTP · WebSocket · Async AI Workflow Orchestrator Planner · Transformer · Execution By Ravinderjeet Singh Nagpal
Clean, minimal cover – no external hosting needed (inline SVG).

Introduction

Artificial Intelligence is no longer limited to single-model interactions. Real-world apps often orchestrate multiple LLMs, integrate MCP services, and combine them with custom tools — all in one flow. The challenge is putting this together without heavy frameworks, glue code, or slow startup.

AI Workflow Orchestrator solves this with a lightweight, Spring Boot–friendly approach: multi-LLM support, @AiTool local tools, MCP clients, dynamic planning, schema transformations, and both CLI/Web execution — with zero boilerplate.

Table of Contents

๐Ÿš€ Features

  • ๐Ÿง  Multi-LLM Support: OpenAI, Anthropic, and Ollama via custom HTTP clients
  • ⚙️ Dynamic Workflow Planning: AI-driven step orchestration
  • ๐Ÿ”Œ MCP Protocol Support: HTTP, WebSocket & Async clients
  • ๐Ÿ› ️ Tool Integration: Register & invoke @AiTool methods
  • ๐Ÿ”„ Schema Transformation: JSON schema-based conversions
  • ๐Ÿ–ฅ️ CLI & Web Modes: Dual execution interfaces
  • ๐Ÿงฉ Intelligent Transformations: LLM-powered data conversions
  • ๐Ÿชถ Lightweight: No external AI framework dependencies
  • Performance: Direct HTTP API calls with Java HttpClient

๐Ÿ“ Project Structure

SpringAIOrchestrator/
├── ai-orchestrator-bom/                 # Bill of Materials & Core Framework
│   └── ai-orchestrator-core/            # Core orchestration engine
├── examples/                            # Example workflow implementations
│   ├── ai-travel-workflow/              # Travel planning workflow example
│   ├── ai-resume_builder-workflow/      # Resume building workflow example
│   └── ai-document_summarizer-workflow/ # Summarizing + classification
├── LICENSE
├── README.md
└── USAGE.md

๐Ÿ› ️ Quick Start

✅ Prerequisites

  • ☕ Java 21+
  • ๐Ÿ“ฆ Maven 3.8+
  • ๐Ÿ”‘ API Keys (OpenAI / Anthropic / Ollama)
  • ๐Ÿง  Local Ollama Installation (optional but recommended)

⚙️ Code Installation

# 1) Clone
git clone <repository-url>
cd SpringAIOrchestrator/spring-ai-orchestrator

# 2) Build the framework
cd ai-orchestrator-bom
mvn clean install

# 3) Env Vars
export OPENAI_API_KEY="your-openai-key"
export ANTHROPIC_API_KEY="your-anthropic-key"
export OLLAMA_BASE_URL="http://localhost:11434"
export SERVER_PORT=8282
export CLI_MODE=false
export APP_NAME="ai-orchestrator"
export PLANNER_FALLBACK=true
export PLANNER_MAX_ITERATIONS=5
export PLANNER_TARGET_RANK=10

# 4) Run an example
cd ../examples/ai-travel-workflow
mvn spring-boot:run

# or
cd ../ai-resume_builder-workflow
mvn spring-boot:run

๐Ÿง  Local LLM Setup with Ollama

The framework can run fully offline using Ollama, letting you test workflows locally without API keys or cloud costs.

Install Ollama

# macOS
brew install ollama
# Linux
curl -fsSL https://ollama.com/install.sh | sh

Windows: Download the installer from ollama.com/download.

Using Ollama for Local (Free) Models

  • Ensure Ollama server is running at http://localhost:11434
  • Verify by opening http://localhost:11434 in a browser
  • Ollama models are quantized by default (e.g., q4); choose tags if needed

Common Pull Commands & Config

GoalOllama CLImodels.yml
Pull Default (q4) ollama pull llama2 modelName: "llama2"
Pull Specific (e.g., 3-bit) ollama pull llama2:7b-q3_K_L modelName: "llama2:7b-q3_K_L"
Pull Latest ollama pull llama3 modelName: "llama3"
Coder Model ollama pull qwen2.5-coder:14b-instruct-q3_K_L modelName: "qwen2.5-coder:14b-instruct-q3_K_L"
Lightweight ollama pull mistral modelName: "mistral"

Local Models Config Example

models:
  - alias: "local"
    provider: "ollama"
    modelName: "llama2"
    baseUrl: "http://localhost:11434"
    enabled: true

Using Ollama Cloud Models

# Sign in
ollama signin

# Pull a cloud-offloaded model
ollama pull qwen3-coder:480b-cloud
models:
- alias: "default"
  provider: "ollama"
  modelName: "qwen3-coder:480b-cloud"
  baseUrl: "http://localhost:11434"
  enabled: true

- alias: "transformer"
  provider: "ollama"
  modelName: "qwen3-coder:480b-cloud"
  baseUrl: "http://localhost:11434"
  enabled: true

๐ŸŒ API Usage

Run Travel Workflow

curl -X POST "http://localhost:8282/api/workflows/run/travel-planner" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "prompt=Plan a 5-day trip to Tokyo in March with budget of $3000"

curl -X POST "http://localhost:8282/api/workflows/run/travel-planner" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "prompt=Business trip to London for 3 days, need flights and hotel recommendations"

Run Resume Workflow

curl -X POST "http://localhost:8282/api/workflows/run/resume-builder" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "prompt=Create resume for Senior Java Developer with 5 years Spring Boot experience"

curl -X POST "http://localhost:8282/api/workflows/run/resume-builder" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "prompt=Build resume for Data Scientist role with Python and ML expertise"

List Workflows

curl -X GET "http://localhost:8282/api/workflows/list"
{
  "travel-planner": "travel-planner - AI-powered travel planning with weather, flights, and cost analysis",
  "resume-builder": "AI Resume Builder - Create a professional resume from user inputs and job descriptions"
}

๐Ÿ—️ Architecture

  • ๐Ÿง  Planner LLM – Generates and ranks intelligent execution plans
  • ๐Ÿ”„ Transformer LLM – Handles format conversions between steps
  • ๐Ÿ”— Custom HTTP Clients – Direct API integration without external AI frameworks
  • ๐Ÿชถ Zero Heavy Dependencies – No LangChain4j or similar
┌─────────────────────────────────────────────────────────────────────────┐
│                        AI Orchestrator Framework                        │
└─────────────────────────────────────────────────────────────────────────┘

┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│ User Input   │  │ REST API     │  │ CLI Mode     │
└──────┬───────┘  └──────┬───────┘  └──────┬───────┘
       │                 │                 │
       └─────────────────┼─────────────────┘
                         │
               ┌─────────▼─────────┐
               │ Workflow Controller│
               └─────────┬─────────┘
                         │
              ┌──────────▼──────────┐
              │ Dynamic Engine (AI) │
              └──────────┬──────────┘
                         │
           ┌─────────────▼─────────────┐
           │  ๐Ÿง  Planner + ๐Ÿ”„ Transformer │
           └─────────────┬─────────────┘
                         │
           ┌─────────────▼─────────────┐
           │    Step Execution Engine   │
           └────────────────────────────┘
LLMs: OpenAI · Anthropic · Ollama Local Tools: @AiTool methods MCP Services via Clients AI Workflow Orchestrator Planner · Transformer · Execution Outputs Apps · APIs · Dashboards · Reports
Everything connected: LLMs + @AiTool local tools + MCP services → Orchestrator → Outputs.

๐Ÿ”Œ Workflow Types & Step Types

Workflow Types

  • ๐Ÿ” Sequential – Predefined step order
  • ๐Ÿง  Dynamic – AI-planned execution order

Step Types

  • ๐Ÿค– LLM – Language model interactions
  • ๐Ÿ”ง Tool – Custom @AiTool methods
  • ๐ŸŒ MCP – External service calls (HTTP, WebSocket, Async)

⚡ Plug & Play Workflow Creation

  1. Add Dependency
<dependency>
  <groupId>codetumblr.net.ai.orchestrator</groupId>
  <artifactId>ai-orchestrator-core</artifactId>
  <version>1.0-SNAPSHOT</version>
</dependency>
  1. Create Application
@SpringBootApplication
@ComponentScan({"codetumblr.net.ai.orchestrator.core", "your.package"})
public class MyWorkflowApplication {
  public static void main(String[] args) {
    SpringApplication.run(MyWorkflowApplication.class, args);
  }
}
  1. Define Models (models.yml)
models:
  - alias: "default"
    provider: "openai"
    model: "gpt-4"
    apiKey: "${OPENAI_API_KEY}"
  1. Create Workflow (workflows/my-workflow.yaml)
id: "document-analyzer"
executionMode: "dynamic"
steps:
  - id: "extract_content"
    type: "tool"
    parameters:
      tool: "document_extractor"
  - id: "analyze_sentiment"
    type: "llm"
    parameters:
      model: "default"
      prompt: "Analyze sentiment: {input}"
  1. Add Tools
@Component
public class DocumentTools {
  @AiTool(name = "document_extractor")
  public String extractText(String filePath) {
    return "Extracted content...";
  }
}
  1. Run
mvn spring-boot:run

๐Ÿ“Š Real-World Plug-and-Play Workflow Examples

  • ๐Ÿ›ซ Travel Planner – Multi-day itineraries with weather, flights, and cost analysis
  • ๐Ÿ“„ Resume Builder – Tailored resumes from job descriptions/skills
  • ๐Ÿ“œ Document Summarizer – Extract, summarize, classify, and store metadata (PDF, DOCX, etc.) using a dynamic workflow

๐Ÿ“‚ Sample Workflow Implementations

Below are some practical examples showing how the AI Workflow Orchestrator can be extended with custom tools, MCP services, and dynamic orchestration — all without additional boilerplate.


๐Ÿ“‘ Example 1: Document Analyzer Workflow

This workflow demonstrates how to build an AI-powered document analyzer that extracts text, summarizes content, classifies it into categories, and stores metadata — all in a single orchestration pipeline.


id: "document-analyzer"
name: "AI Document Analyzer & Classifier"
description: "Extract, summarize, classify, and persist document insights."
version: "1.0"
executionMode: "dynamic"
outputMode: "all"

steps:
  - id: "extract_text"
    type: "mcp"
    description: "Extract text from documents with OCR fallback."
    parameters:
      client: "doc-processor"
      service: "extract_text"

  - id: "summarize_content"
    type: "llm"
    description: "Generate a human-readable summary."
    parameters:
      model: "default"
      promptTemplate: "prompts/document/summarize.txt"

  - id: "suggest_categories"
    type: "tool"
    description: "Suggest relevant categories based on content."
    parameters:
      tool: "suggest_categories"

  - id: "classify_document"
    type: "llm"
    description: "Classify into the most relevant category."
    parameters:
      model: "default"
      promptTemplate: "prompts/document/classify.txt"

  - id: "store_metadata"
    type: "tool"
    description: "Persist classification and summary results."
    parameters:
      tool: "save_document_metadata"
---

๐Ÿ› ️ Example 2: Local Tool - Category Suggestion

Local tools can be created with @AiTool to enrich workflows. Here’s a sample tool that suggests relevant categories for a given document text.


@Component
public class CategoryTool {

    @AiTool(
        name = "suggest_categories",
        description = "Suggest relevant document categories based on content."
    )
    public List suggestCategories(String text) {
        return List.of("Finance", "Healthcare", "Legal", "Technology");
    }
}
---

๐ŸŒ Example 3: Internal MCP Service - Document Text Extraction

MCP services allow external-like service calls to be part of the same workflow. The example below shows how to implement a document extraction service with OCR fallback.


@MCPService(
    name = "doc-processor",
    description = "Extract text from documents and scanned PDFs."
)
public class DocumentProcessor {

    @MCPMethod(
        name = "extract_text",
        description = "Extracts text with auto-detection and OCR fallback."
    )
    public Map extractText(String docName, String type, String base64Content) {
        // Example implementation: decode + process content
        Map result = new HashMap<>();
        result.put("document", docName);
        result.put("text", "Extracted content goes here...");
        result.put("status", "Success");
        return result;
    }
}
---

๐Ÿ“Œ Why These Matter

These examples demonstrate how easily you can:

  • ๐Ÿ” Combine LLM, local tools, and MCP services into one workflow.
  • ⚙️ Extend capabilities with zero boilerplate using @AiTool and @MCPService.
  • ๐ŸŒ Enable both internal and external integrations within the same orchestration engine.

Upcoming Examples (Planned)

  • ๐Ÿง  Intelligent Chat Agent
  • ๐Ÿ“ˆ Financial Report Analyzer
  • ๐Ÿงช Code Review Assistant

๐Ÿ–ฅ️ UI / Web Integration — Document Summarizer

The framework supports Spring Boot web controllers for file upload and dynamic prompt generation.

How it works: Upload → Base64 encode → Build planner prompt → Review → Submit to Orchestrator → Planner routes to initial MCP step (extract_text).

Run the Web Example

cd examples/ai-document_summarizer-workflow
mvn spring-boot:run

Open: http://localhost:8383/

Key Endpoints

EndpointMethodDescription
/GETUpload form
/generate-promptPOSTBase64 encodes file, builds planner prompt
/submit-promptPOSTSubmits to /api/workflows/run/document-summarizer

⚙️ Advanced Configuration Options

application.yml

server:
  port: ${SERVER_PORT:8282}
spring:
  application:
    name: ${APP_NAME:ai-orchestrator-document-summarizer}
 ...

ai:
  orchestrator:
    workflows:
      path: ${WORKFLOWS_PATH:classpath*:workflows/*-workflow.yaml}
      prompt:
        path: ${PLANNER_PROMPT_PATH:}
    transformer:
      prompt:
        path: ${TRANSFORMER_PROMPT_PATH:}
    mcp:
      clients:
        path: classpath:${MCP_CLIENTS_PATH:/mcp-clients.yml}

mcp-clients.yml

clients:
  # ============================================================
# MCP Clients Configuration for Document Summarizer Workflow
# ============================================================
# This configuration defines the MCP services used for text extraction.
# All other steps (summarization, classification, metadata storage)
# are handled by LLMs or tools within the orchestrator.
#
# Environment variables can override default values for flexibility.
# ============================================================

clients:
  # ----------------------------------------------------------
  # Document Processor Service (Primary MCP for Text Extraction)
  # ----------------------------------------------------------
  - name: "document-processor"
    endpoint: "${MCP_DOCUMENT_PROCESSOR_ENDPOINT:http://localhost:8383}"
    service: "extract_text"
    protocol: "${MCP_DOCUMENT_PROCESSOR_PROTOCOL:http}"
    timeout: "${MCP_DOCUMENT_PROCESSOR_TIMEOUT:15000}"   # Default: 15s timeout
    auth:
      type: "${MCP_DOCUMENT_PROCESSOR_AUTH_TYPE:none}"  # Supported: none, basic, oauth2, api-key, jwt

      # --- Basic Auth (Optional) ---
      username: "${MCP_DOCUMENT_PROCESSOR_USERNAME:}"
      password: "${MCP_DOCUMENT_PROCESSOR_PASSWORD:}"

      # --- API Key Auth (Optional) ---
      apiKey: "${MCP_DOCUMENT_PROCESSOR_API_KEY:}"
      apiKeyHeader: "${MCP_DOCUMENT_PROCESSOR_API_KEY_HEADER:X-API-Key}"

      # --- OAuth2 (Optional) ---
      tokenUri: "${MCP_DOCUMENT_PROCESSOR_TOKEN_URI:}"
      clientId: "${MCP_DOCUMENT_PROCESSOR_CLIENT_ID:}"
      clientSecret: "${MCP_DOCUMENT_PROCESSOR_CLIENT_SECRET:}"
      scope: "${MCP_DOCUMENT_PROCESSOR_SCOPE:}"

      # --- JWT Auth (Optional) ---
      jwtIssuer: "${MCP_DOCUMENT_PROCESSOR_JWT_ISSUER:}"
      jwtSubject: "${MCP_DOCUMENT_PROCESSOR_JWT_SUBJECT:}"
      jwtSecret: "${MCP_DOCUMENT_PROCESSOR_JWT_SECRET:}"

    enabled: "${MCP_DOCUMENT_PROCESSOR_ENABLED:true}"

models.yml

config:
  defaultMaxTokens: 1000
  promptTruncateLength: 50
  descriptionTruncateLength: 30
  autoRegisterForPlugins: true

models:
  - alias: "default"
    provider: "ollama"
    modelName: "qwen3-coder:480b-cloud"
    baseUrl: "http://localhost:11434"
    temperature: 0.7
    maxTokens: 2000
    enabled: true

  - alias: "openai"
    provider: "openai"
    modelName: "gpt-4o-mini"
    apiKey: "${OPENAI_API_KEY}"
    temperature: 0.7
    maxTokens: 4000
    enabled: true

  - alias: "planner"
    provider: "ollama"
    modelName: "qwen2.5-coder:14b-instruct-q3_K_L"
    baseUrl: "http://localhost:11434"
    temperature: 0.3
    maxTokens: 1500
    enabled: true

  - alias: "transformer"
    provider: "ollama"
    modelName: "qwen3-coder:480b-cloud"
    baseUrl: "http://localhost:11434"
    temperature: 0.1
    maxTokens: 1000
    enabled: true

๐Ÿงช CLI Mode

export CLI_MODE=true
mvn spring-boot:run
# or
CLI_MODE=true mvn spring-boot:run
# or
java -DCLI_MODE=true -jar ai-travel-workflow-1.0-SNAPSHOT.jar

Commands

# List workflows
lw

# Interactive
interactive
i
run-interactive

# Run specific
run --workflow-id travel-planner --prompt "Plan weekend trip to Paris"
run-workflow --workflow-id resume-builder --prompt "Create resume for DevOps engineer"

# Quick run
quick --number 1
q --number 2

# Help / Logs
help
h
?
log-info
logs
debug-help

# Exit
exit
quit
bye

๐Ÿงฐ Logging

logging:
  config: classpath:log4j2.xml

⏱️ Timeouts

# Planner (configurable)
ai:
  orchestrator:
    planner:
      max-iterations: 5
      target-rank: 10
      fallback-enabled: true

# MCP client timeouts (per client)
clients:
  - name: "weather-services-api"
    timeout: "5000"
  - name: "flight-services-api"
    timeout: "5000"
Hardcoded timeouts (not config-based yet):
LLM Planning Timeout: 120s · Planning Session Timeout: 60s · LLM Client Timeouts: 5m request / 30s connect · Schema Caching: ConcurrentHashMap · HTTP Client: Java 21 HttpClient

๐Ÿ”ง Environment Variables Reference

Core Application

export SERVER_PORT=8282
export CLI_MODE=false
export APP_NAME="ai-orchestrator"

LLM API Keys

export OPENAI_API_KEY="sk-your-openai-key"
export ANTHROPIC_API_KEY="sk-ant-your-anthropic-key"
export OLLAMA_BASE_URL="http://localhost:11434"

Planner Configuration

export PLANNER_FALLBACK=true
export PLANNER_MAX_ITERATIONS=5
export PLANNER_TARGET_RANK=10
export STEP_SEPARATOR=","
export PLANNER_PROMPT_PATH=""
export TRANSFORMER_PROMPT_PATH=""

File Paths

export WORKFLOWS_PATH="classpath*:workflows/*-workflow.yaml"
export MODELS_PATH="/models.yml"
export MCP_CLIENTS_PATH="/mcp-clients.yml"

Logging Levels

export PLANNER_LOG_LEVEL=INFO
export ENGINE_LOG_LEVEL=INFO
export WORKFLOW_LOG_LEVEL=INFO
export MCP_SERVICE_LOG_LEVEL=INFO
export SCHEMA_LOG_LEVEL=INFO

๐Ÿ†˜ Troubleshooting

IssueSolution
Schema not foundVerify schema files exist in resources/schemas/
LLM client not availableCheck API keys and network connectivity
Workflow not foundEnsure workflow YAML is in resources/workflows/
Tool execution failedVerify tool parameters and implementation
MCP service timeoutCheck MCP client configuration and endpoints
Planning failedEnable planner fallback: PLANNER_FALLBACK=true

Health Checks

curl -X GET "http://localhost:8282/api/workflows/list"
echo $OPENAI_API_KEY
echo $ANTHROPIC_API_KEY
echo $OLLAMA_BASE_URL

Debug Steps

# Enable debug
export PLANNER_LOG_LEVEL=DEBUG
export ENGINE_LOG_LEVEL=DEBUG
export WORKFLOW_LOG_LEVEL=DEBUG

# Tail logs
tail -f logs/ai-orchestrator-**.log

# Validate YAML
cat src/main/resources/models.yml
cat src/main/resources/mcp-clients.yml

๐Ÿ“„ License

Licensed under the MIT License. See LICENSE in the repository.

๐Ÿ‘จ‍๐Ÿ’ป Author

Ravinderjeet Singh Nagpal
Building next-generation AI orchestration systems.

๐Ÿ“Š Performance Features

  • No External AI Frameworks — custom HTTP clients instead of LangChain4j
  • Smaller JAR Size — reduced by ~15–20MB
  • Faster Startup — no auto-configuration overhead
  • Direct API Control — optimized request/response handling

๐Ÿ”— Related Projects

๐Ÿ Conclusion — Build Smarter AI Pipelines

AI Workflow Orchestrator unifies LLMs, @AiTool local tools, and MCP services in a single, lightweight, Spring-friendly framework. With dynamic planning, schema transformations, and direct HTTP clients, it’s a practical foundation for modern AI apps — from document pipelines to enterprise AI agents.

Next Steps

  • Try built-in workflows (Travel Planner, Resume Builder, Document Summarizer)
  • Create your own workflow YAML in minutes
  • Run locally with Ollama or integrate with cloud LLMs

Have ideas or feedback? Share them in the comments — I’d love to hear how you’re building AI workflows.

© 2025 • AI Workflow Orchestrator • Article by Ravinderjeet Singh Nagpal

Java Equals and Java hasCode functions for deep Comparasion


import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;
 
public class EqualsTest implements  Comparator
{
    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public Integer getAge()
    {
        return age;
    }

    public void setAge(Integer age)
    {
        this.age = age;
    }

    private String    name;
    private Integer    age;

    public EqualsTest()
    {
        this.name = "Ravinder";
        this.age = 0;
    }

    public EqualsTest(String name, Integer age)
    {
        this.name = name;
        this.age = age;

    }

    @Override
    public String toString()
    {
        StringBuffer sb = new StringBuffer();

        sb.append("My name is " + this.getName() + " having an age "
                + this.getAge());

        return sb.toString();

    }

    public static void main(String p[])
    {
        EqualsTest equalsTest = new EqualsTest();

        EqualsTest equalsTest1 = new EqualsTest("Ravinder1", 1);

        EqualsTest equalsTest2 = new EqualsTest("Ravinder2", 2);

        EqualsTest equalsTest3 = new EqualsTest("Ravinder3", 3);

        EqualsTest equalsTest4 = new EqualsTest("Ravinder4", 4);

        EqualsTest equalsTest5 = new EqualsTest("Ravinder5", 5);

        EqualsTest equalsTest6 = new EqualsTest("Ravinder6", 6);

        EqualsTest equalsTest7 = new EqualsTest("Ravinder7", 7);

        EqualsTest equalsTest8 = new EqualsTest("Ravinder8", 8);

        EqualsTest equalsTest9 = new EqualsTest("Ravinder9", 9);

        // System.out.println(equalsTest);
        // System.out.println(equalsTest1);

        // System.out.println("Shallow comparasion ==>"
        // + (equalsTest == equalsTest1));
        // System.out.println("Deep comparasion ==>"
        // + equalsTest.equals(equalsTest1));

        // System.out.println(equalsTest.hashCode());
        // System.out.println(equalsTest1.hashCode());

        Set hashSet = new HashSet(10);

        hashSet.add(equalsTest);
        hashSet.add(equalsTest1);
        hashSet.add(equalsTest2);
        hashSet.add(equalsTest3);
        hashSet.add(equalsTest4);
        hashSet.add(equalsTest5);
        hashSet.add(equalsTest6);
        hashSet.add(equalsTest7);
        hashSet.add(equalsTest8);
        hashSet.add(equalsTest9);

        Set linkedHashSet = new LinkedHashSet(10);

        linkedHashSet.add(equalsTest);
        linkedHashSet.add(equalsTest1);
        linkedHashSet.add(equalsTest2);
        linkedHashSet.add(equalsTest3);
        linkedHashSet.add(equalsTest4);
        linkedHashSet.add(equalsTest5);
        linkedHashSet.add(equalsTest6);
        linkedHashSet.add(equalsTest7);
        linkedHashSet.add(equalsTest8);
        linkedHashSet.add(equalsTest9);

        Set treeSet = new TreeSet(new EqualsTest());

        treeSet.add(equalsTest);
        treeSet.add(equalsTest1);
        treeSet.add(equalsTest2);
        treeSet.add(equalsTest3);
        treeSet.add(equalsTest4);
        treeSet.add(equalsTest5);
        treeSet.add(equalsTest6);
        treeSet.add(equalsTest7);
        treeSet.add(equalsTest8);
        treeSet.add(equalsTest9);

        if (hashSet.contains(equalsTest))
        {
            System.out.println("The object already exist in the set");

        }
        else
        {
            hashSet.add(equalsTest);
            System.out.println("The object already exist in the set");
        }

        System.out.println("The actual size of the hashset is---> "
                + hashSet.size());

        System.out.println("The values in the hashset are -->"
                + hashSet.toString());

        System.out.println("The actual size of the linkedHashSet is---> "
                + linkedHashSet.size());

        System.out.println("The values in the linkedHashSet are -->"
                + linkedHashSet.toString());

        System.out.println("The actual size of the treeSet is---> "
                + treeSet.size());

        System.out.println("The values in the treeSet are -->"
                + treeSet.toString());
    }

    @Override
    public int hashCode()
    {
        int hashcode = this.getAge().hashCode() + this.getName().hashCode();

        return hashcode;
    }

    @Override
    public boolean equals(Object obj)
    {
        boolean isEqual = false;

        if (obj == null)
        {
            return false;
        }

        if (this.getClass() == obj.getClass())
        {
            EqualsTest equalsTest = (EqualsTest) obj;

            if (this.getName().equals(equalsTest.getName())
                    && (this.getAge().equals(equalsTest.getAge())))
            {
                return true;
            }

        }
        return isEqual;

    }

    // this function is declare in Comparator interface, need to sort the
    // collection, comparator instance must be given to TreeSet constructor.
    @Override
    public int compare(Object o1, Object o2)
    {
        EqualsTest equalsTestObj1 = (EqualsTest) o1;

        EqualsTest equalsTestObj2 = (EqualsTest) o2;

        if (equalsTestObj1.getAge() > equalsTestObj2.getAge())
        {
            return 1;
        }
        else if (equalsTestObj1.getAge() < equalsTestObj2.getAge())
        {
            return -1;
        }
        else
            return 0;
    }

}

Java Code for Connection Pooling / Connection Pooling in Java

public class MyConnection {

private boolean inUse ;

public MyConnection() {
this.inUse = false;
}

public void setInUse()
{
this.inUse = true;
}

public void setNotInUse()
{
this.inUse = false;
}


public boolean isInUse() {
return inUse;
}

}


import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;

public class MyconnectionPool
{

private static HashSet connSet;
private static final int defaultSize = 10;
private int maxPoolSize = 10;
private static MyconnectionPool myconnectionPool;

static
{

connSet = (HashSet) Collections
.synchronizedSet(new HashSet(defaultSize));

int connCounter = 0;

while (connCounter < defaultSize)
{
connSet.add(new MyConnection());
}

}

public static MyconnectionPool getInstance()
{

if (myconnectionPool == null)
{
myconnectionPool = new MyconnectionPool();
}

return myconnectionPool;
}

public MyConnection acquireConnection() throws Exception
{

if (connSet != null)
{
if (connSet.isEmpty())
{
throw new Exception("Connection Pool is empty");
}
else
{
synchronized (connSet)
{

Iterator connIterator = connSet.iterator();

MyConnection myConn = null;

while (connIterator.hasNext())
{
myConn = connIterator.next();

if (myConn.isInUse())
{
continue;
}
else
{
return myConn;
}
}

if (connSet.size() < maxPoolSize)
{
myConn = new MyConnection();

myConn.setInUse();

connSet.add(myConn);

return myConn;
}
else
{
throw new Exception("Connection Pool is full ");
}

}

}
}
else
{
throw new Exception("Connection Pool is not initialised");
}
}
}

SWING PROGRESS MONITOR (JPROGRESSMONITOR)

package progressmonitorexample;

import javax.swing.*;
import java.awt.event.*;
import java.beans.*;
import java.io.*;
import java.awt.Insets;
import java.awt.BorderLayout;
import java.util.*;
import java.util.concurrent.*;

public class ProgressMonitorExample extends JPanel implements ActionListener, PropertyChangeListener {
private static final int DEFAULT_WIDTH = 700;
private static final int DEFAULT_HEIGHT = 350;
private JButton copyButton;
private JTextArea console;
private ProgressMonitor progressMonitor;
private CopyFiles operation;

public static void main(String[] args) {
// tell the event dispatch thread to schedule the execution
// of this Runnable (which will create the example app GUI) for a later time
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// create example app window
JFrame frame = new JFrame("Progress Monitor Example");
// application will exit on close
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);

// create example app content pane
// ProgressMonitorExample constructor does additional GUI setup
JComponent contentPane = new ProgressMonitorExample();
contentPane.setOpaque(true);
frame.setContentPane(contentPane);

// display example app window
frame.setVisible(true);
}
});
}

public ProgressMonitorExample() {
// set up the copy files button
copyButton = new JButton("Copy Files");
copyButton.addActionListener(this);
JPanel buttonPanel = new JPanel();
buttonPanel.add(copyButton);

// set up the console for display of operation output
console = new JTextArea(15,60);
console.setMargin(new Insets(5,5,5,5));
console.setEditable(false);
add(new JScrollPane(console), BorderLayout.CENTER);
add(buttonPanel, BorderLayout.SOUTH);
}

public void actionPerformed(ActionEvent event) {
// make sure there are files to copy
File srcDir = new File("in");
if (srcDir.exists() && (srcDir.listFiles() != null && srcDir.listFiles().length > 0)) {
// set up the destination directory
File destDir = new File("out");
// create the progress monitor
progressMonitor = new ProgressMonitor(ProgressMonitorExample.this,
"Operation in progress...",
"", 0, 100);
progressMonitor.setProgress(0);

// schedule the copy files operation for execution on a background thread
operation = new CopyFiles(srcDir, destDir);
// add ProgressMonitorExample as a listener on CopyFiles;
// of specific interest is the bound property progress
operation.addPropertyChangeListener(this);
operation.execute();
// we're running our operation; disable copy button
copyButton.setEnabled(false);
} else {
console.append("The sample application needs files to copy."
+ " Please add some files to the in directory"
+ " located at the project root.");
}
}

// executes in event dispatch thread
public void propertyChange(PropertyChangeEvent event) {
// if the operation is finished or has been canceled by
// the user, take appropriate action
if (progressMonitor.isCanceled()) {
operation.cancel(true);
} else if (event.getPropertyName().equals("progress")) {
// get the % complete from the progress event
// and set it on the progress monitor
int progress = ((Integer)event.getNewValue()).intValue();
progressMonitor.setProgress(progress);
}
}

class CopyFiles extends SwingWorker {
private static final int PROGRESS_CHECKPOINT = 10000;
private File srcDir;
private File destDir;

CopyFiles(File src, File dest) {
this.srcDir = src;
this.destDir = dest;
}

// perform time-consuming copy task in the worker thread
@Override
public Void doInBackground() {
int progress = 0;
// initialize bound property progress (inherited from SwingWorker)
setProgress(0);
// get the files to be copied from the source directory
File[] files = srcDir.listFiles();
// determine the scope of the task
long totalBytes = calcTotalBytes(files);
long bytesCopied = 0;

while (progress < 100 && !isCancelled()) {
// copy the files to the destination directory
for (File f : files) {
File destFile = new File(destDir, f.getName());
long previousLen = 0;

try {
InputStream in = new FileInputStream(f);
OutputStream out = new FileOutputStream(destFile);
byte[] buf = new byte[1024];
int counter = 0;
int len;

while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
counter += len;
bytesCopied += (destFile.length() - previousLen);
previousLen = destFile.length();
if (counter > PROGRESS_CHECKPOINT || bytesCopied == totalBytes) {
// get % complete for the task
progress = (int)((100 * bytesCopied) / totalBytes);
counter = 0;
CopyData current = new CopyData(progress, f.getName(),
getTotalKiloBytes(totalBytes),
getKiloBytesCopied(bytesCopied));

// set new value on bound property
// progress and fire property change event
setProgress(progress);

// publish current progress data for copy task
publish(current);
}
}
in.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

return null;
}

// process copy task progress data in the event dispatch thread
@Override
public void process(List data) {
if(isCancelled()) { return; }
CopyData update = new CopyData(0, "", 0, 0);
for (CopyData d : data) {
// progress updates may be batched, so get the most recent
if (d.getKiloBytesCopied() > update.getKiloBytesCopied()) {
update = d;
}
}

// update the progress monitor's status note with the
// latest progress data from the copy operation, and
// additionally append the note to the console
String progressNote = update.getKiloBytesCopied() + " of "
+ update.getTotalKiloBytes() + " kb copied.";
String fileNameNote = "Now copying " + update.getFileName();

if (update.getProgress() < 100) {
progressMonitor.setNote(progressNote + " " + fileNameNote);
console.append(progressNote + "\n" + fileNameNote + "\n");
} else {
progressMonitor.setNote(progressNote);
console.append(progressNote + "\n");
}
}

// perform final updates in the event dispatch thread
@Override
public void done() {
try {
// call get() to tell us whether the operation completed or
// was canceled; we don't do anything with this result
Void result = get();
console.append("Copy operation completed.\n");
} catch (InterruptedException e) {

} catch (CancellationException e) {
// get() throws CancellationException if background task was canceled
console.append("Copy operation canceled.\n");
} catch (ExecutionException e) {
console.append("Exception occurred: " + e.getCause());
}
// reset the example app
copyButton.setEnabled(true);
progressMonitor.setProgress(0);
}

private long calcTotalBytes(File[] files) {
long tmpCount = 0;
for (File f : files) {
tmpCount += f.length();
}
return tmpCount;
}

private long getTotalKiloBytes(long totalBytes) {
return Math.round(totalBytes / 1024);
}

private long getKiloBytesCopied(long bytesCopied) {
return Math.round(bytesCopied / 1024);
}
}

class CopyData {
private int progress;
private String fileName;
private long totalKiloBytes;
private long kiloBytesCopied;

CopyData(int progress, String fileName, long totalKiloBytes, long kiloBytesCopied) {
this.progress = progress;
this.fileName = fileName;
this.totalKiloBytes = totalKiloBytes;
this.kiloBytesCopied = kiloBytesCopied;
}

int getProgress() {
return progress;
}

String getFileName() {
return fileName;
}

long getTotalKiloBytes() {
return totalKiloBytes;
}

long getKiloBytesCopied() {
return kiloBytesCopied;
}
}
}

READING XML THROUGH JAVASCRIPT

READING XML THROUGH JAVASCRIPT

XML.load = function(url) {
var xmldoc = XML.newDocument();
xmldoc.async = false;
xmldoc.load(url);
return xmldoc;
};
XML.newDocument = function(rootTagName, namespaceURL) {
if (!rootTagName) rootTagName = "";
if (!namespaceURL) namespaceURL = "";
if (document.implementation && document.implementation.createDocument) {
// This is the W3C standard way to do it
return document.implementation.createDocument(namespaceURL,
rootTagName, null);
}
else { // This is the IE way to do it
// Create an empty document as an ActiveX object
// If there is no root element, this is all we have to do
var doc = new ActiveXObject("MSXML2.DOMDocument");

// If there is a root tag, initialize the document
if (rootTagName) {
// Look for a namespace prefix
var prefix = "";
var tagname = rootTagName;
var p = rootTagName.indexOf(':');


if (p != -1) {
prefix = rootTagName.substring(0, p);
tagname = rootTagName.substring(p+1);
}

// If we have a namespace, we must have a namespace prefix
// If we don't have a namespace, we discard any prefix
if (namespaceURL) {
if (!prefix) prefix = "a0"; // What Firefox uses
}
else prefix = "";

// Create the root element (with optional namespace) as a
// string of text
var text = "<" + (prefix?(prefix+":"):"") + tagname +
(namespaceURL
?(" xmlns:" + prefix + '="' + namespaceURL +'"')
:"") +
"/>";
// And parse that text into the empty document
doc.loadXML(text);
}
return doc;
}
};



file: readxml.js
function readXmlFile() {
url = 'http://rorbuilder.info/pl/test123';

doc = XML.load(url);
alert(doc.documentElement.firstChild.nextSibling.firstChild.nodeValue);
}

SWING JTREE EXAMPLE

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;

public class JTreeDemo
{
public static void main(String [] arg)
{
JTreeDemo obj = new JTreeDemo();
}

public JTreeDemo()
{
JFrame frame = new JFrame("JTree Demo");
Container c = frame.getContentPane();
c.setLayout( new BorderLayout() );

//Create top node of a tree
final DefaultMutableTreeNode top = new DefaultMutableTreeNode("Course");

//Create a subtree UG
final DefaultMutableTreeNode UG = new DefaultMutableTreeNode("UG");
top.add(UG);
final DefaultMutableTreeNode a1 = new DefaultMutableTreeNode("B.E");
UG.add(a1);
final DefaultMutableTreeNode a2 = new DefaultMutableTreeNode("B.C.A");
UG.add(a2);
final DefaultMutableTreeNode a3 = new DefaultMutableTreeNode("B.Sc");
UG.add(a3);
final DefaultMutableTreeNode a4 = new DefaultMutableTreeNode("B.Com");
UG.add(a4);
final DefaultMutableTreeNode a5 = new DefaultMutableTreeNode("B.A");
UG.add(a5);



//Create a subtree PG
final DefaultMutableTreeNode PG = new DefaultMutableTreeNode("PG");
top.add(PG);
final DefaultMutableTreeNode b1 = new DefaultMutableTreeNode("M.E");
PG.add(b1);
final DefaultMutableTreeNode b2 = new DefaultMutableTreeNode("M.C.A");
PG.add(b2);
final DefaultMutableTreeNode b3 = new DefaultMutableTreeNode("M.Sc");
PG.add(b3);
final DefaultMutableTreeNode b4 = new DefaultMutableTreeNode("M.Com");
PG.add(b4);
final DefaultMutableTreeNode b5 = new DefaultMutableTreeNode("M.A");
PG.add(b5);

//Creating tree
final JTree tree = new JTree(top);

int v = ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED;
int h = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED;
final JScrollPane jsp = new JScrollPane(tree,v,h);
c.add(jsp,BorderLayout.CENTER );

final JTextField text = new JTextField("",20);
c.add(text,BorderLayout.SOUTH);

tree.addMouseListener( new MouseAdapter()
{
public void mouseClicked( MouseEvent me)
{
TreePath tp = tree.getPathForLocation(me.getX(),me.getY() );
if( tp != null )
text.setText(tp.toString() );
else
text.setText("");
}
}
);

frame.setSize(300,200);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}

SWING JSLIDER EXAMPLE

E

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;

public class JSliderDemo
{
public static void main(String[] a)
{

JFrame frame = new JFrame("JSlider Demo");
Container c = frame.getContentPane();
c.setLayout( new FlowLayout() );

final JTextField text = new JTextField("A picture worth more than thousands words" );
text.setFont(new Font("Serif",Font.PLAIN,30));
text.setEditable(false);

final JSlider fontSizeSlider = new JSlider(SwingConstants.HORIZONTAL,0,45,30);
fontSizeSlider.setMajorTickSpacing(1);

fontSizeSlider.addChangeListener( new ChangeListener()
{
public void stateChanged(ChangeEvent ce)
{
int fontSize;
fontSize = fontSizeSlider.getValue();
text.setFont( new Font("Serif",Font.PLAIN,fontSize));
}
}
);


c.add(text);
c.add(fontSizeSlider);

frame.setSize(550,200);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}

SWING TABBEDPANE EXAMPLE

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class JTabbedPaneDemo
{
public static void main(String[] arg)
{
JTabbedPaneDemo obj = new JTabbedPaneDemo();
}

public JTabbedPaneDemo()
{
JFrame frame = new JFrame("Tabbed pane demo");
Container c = frame.getContentPane();


JTabbedPane jtp = new JTabbedPane();
jtp.addTab("Country", new CountryPanel() );
jtp.addTab("State", new StatePanel() );
jtp.addTab("City", new CityPanel() );

c.add(jtp);
frame.setSize(300,300);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}

class CountryPanel extends JPanel
{
public CountryPanel()
{
String item[] = { "India", "China", "UK", "USA", "Russia" };
JComboBox combo = new JComboBox(item);
add(combo);
}
}

class StatePanel extends JPanel
{
public StatePanel()
{
JButton b1 = new JButton("Tamil Nadu");
JButton b2 = new JButton("Maharastra");
JButton b3 = new JButton("Kerala");
add(b1);
add(b2);
add(b3);
}
}


class CityPanel extends JPanel
{
public CityPanel()
{
JCheckBox b1 = new JCheckBox("Chennai");
JCheckBox b2 = new JCheckBox("Delhi");
JCheckBox b3 = new JCheckBox("Mumbai");
add(b1);
add(b2);
add(b3);
}
}

Drag And Drop using javascript


<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>


"http://www.w3.org/TR/html4/loose.dtd">




JSP Page





Click -- > Drag and Drop any item



Item #1


Item #2


Item #3


Item #4












Java Mail Code To Send EMAIL

E-Mailing Through Java Mail

* You use the JavaMail API where as JavaMail implementation providers implement the JavaMail API to give you a JavaMail client (Java JAR file). Sun gives you mail.jar which has Sun's SMTP, POP3 and IMAP client implementations along with the JavaMail API. This is sufficient to send and receive e-mail but not to read or post to newgroups which use NNTP.

Sample Code to Send E-Mail

* To compile and run, you must have mail.jar (from the JavaMail download) and activation.jar (from the JavaBeans Activation Framework download) in Java classpath.

* You need to replace email addresses and mail server with your values where noted. Username and password is generally not needed to send e-mail although your ISP may still require it to prevent spam from going through its systems.

import java.util.*;

import javax.mail.*;

import javax.mail.internet.*;

import javax.activation.*;

// Send a simple, single part, text/plain e-mail

public class TestEmail {

public static void main(String[] args) {

// SUBSTITUTE YOUR EMAIL ADDRESSES HERE!!!

String to = "vipan@vipan.com";

String from = "vipan@vipan.com";

// SUBSTITUTE YOUR ISP'S MAIL SERVER HERE!!!

String host = "smtp.yourisp.net";

// Create properties, get Session

Properties props = new Properties();

// If using static Transport.send(),

// need to specify which host to send it to

props.put("mail.smtp.host", host);

// To see what is going on behind the scene

props.put("mail.debug", "true");

Session session = Session.getInstance(props);

try {

// Instantiatee a message

Message msg = new MimeMessage(session);

//Set message attributes

msg.setFrom(new InternetAddress(from));

InternetAddress[] address = {new InternetAddress(to)};

msg.setRecipients(Message.RecipientType.TO, address);

msg.setSubject("Test E-Mail through Java");

msg.setSentDate(new Date());

// Set message content

msg.setText("This is a test of sending a " +

"plain text e-mail through Java.\n" +

"Here is line 2.");

//Send the message

Transport.send(msg);

}

catch (MessagingException mex) {

// Prints all nested (chained) exceptions as well

mex.printStackTrace();

}

}

}//End of class

Sample Code to Send Multipart E-Mail, HTML E-Mail and File Attachments

* To compile and run, you must have mail.jar (from the JavaMail download) and activation.jar (from the JavaBeans Activation Framework download) in Java classpath.

* You need to replace email addresses and mail server with your values where noted.

* This sample code has debugging turned on ("mail.debug") to see what is going on behind the scenes in JavaMail code.

import java.util.*;

import java.io.*;

import javax.mail.*;

import javax.mail.internet.*;

import javax.activation.*;

public class SendMailUsage {

public static void main(String[] args) {

// SUBSTITUTE YOUR EMAIL ADDRESSES HERE!!!

String to = "you@yourisp.net";

String from = "you@yourisp.net";

// SUBSTITUTE YOUR ISP'S MAIL SERVER HERE!!!

String host = "smtpserver.yourisp.net";

// Create properties for the Session

Properties props = new Properties();

// If using static Transport.send(),

// need to specify the mail server here

props.put("mail.smtp.host", host);

// To see what is going on behind the scene

props.put("mail.debug", "true");

// Get a session

Session session = Session.getInstance(props);

try {

// Get a Transport object to send e-mail

Transport bus = session.getTransport("smtp");

// Connect only once here

// Transport.send() disconnects after each send

// Usually, no username and password is required for SMTP

bus.connect();

//bus.connect("smtpserver.yourisp.net", "username", "password");

// Instantiate a message

Message msg = new MimeMessage(session);

// Set message attributes

msg.setFrom(new InternetAddress(from));

InternetAddress[] address = {new InternetAddress(to)};

msg.setRecipients(Message.RecipientType.TO, address);

// Parse a comma-separated list of email addresses. Be strict.

msg.setRecipients(Message.RecipientType.CC,

InternetAddress.parse(to, true));

// Parse comma/space-separated list. Cut some slack.

msg.setRecipients(Message.RecipientType.BCC,

InternetAddress.parse(to, false));

msg.setSubject("Test E-Mail through Java");

msg.setSentDate(new Date());

// Set message content and send

setTextContent(msg);

msg.saveChanges();

bus.sendMessage(msg, address);

setMultipartContent(msg);

msg.saveChanges();

bus.sendMessage(msg, address);

setFileAsAttachment(msg, "C:/WINDOWS/CLOUD.GIF");

msg.saveChanges();

bus.sendMessage(msg, address);

setHTMLContent(msg);

msg.saveChanges();

bus.sendMessage(msg, address);

bus.close();

}

catch (MessagingException mex) {

// Prints all nested (chained) exceptions as well

mex.printStackTrace();

// How to access nested exceptions

while (mex.getNextException() != null) {

// Get next exception in chain

Exception ex = mex.getNextException();

ex.printStackTrace();

if (!(ex instanceof MessagingException)) break;

else mex = (MessagingException)ex;

}

}

}

// A simple, single-part text/plain e-mail.

public static void setTextContent(Message msg) throws MessagingException {

// Set message content

String mytxt = "This is a test of sending a " +

"plain text e-mail through Java.\n" +

"Here is line 2.";

msg.setText(mytxt);

// Alternate form

msg.setContent(mytxt, "text/plain");

}

// A simple multipart/mixed e-mail. Both body parts are text/plain.

public static void setMultipartContent(Message msg) throws MessagingException {

// Create and fill first part

MimeBodyPart p1 = new MimeBodyPart();

p1.setText("This is part one of a test multipart e-mail.");

// Create and fill second part

MimeBodyPart p2 = new MimeBodyPart();

// Here is how to set a charset on textual content

p2.setText("This is the second part", "us-ascii");

// Create the Multipart. Add BodyParts to it.

Multipart mp = new MimeMultipart();

mp.addBodyPart(p1);

mp.addBodyPart(p2);

// Set Multipart as the message's content

msg.setContent(mp);

}

// Set a file as an attachment. Uses JAF FileDataSource.

public static void setFileAsAttachment(Message msg, String filename)

throws MessagingException {

// Create and fill first part

MimeBodyPart p1 = new MimeBodyPart();

p1.setText("This is part one of a test multipart e-mail." +

"The second part is file as an attachment");

// Create second part

MimeBodyPart p2 = new MimeBodyPart();

// Put a file in the second part

FileDataSource fds = new FileDataSource(filename);

p2.setDataHandler(new DataHandler(fds));

p2.setFileName(fds.getName());

// Create the Multipart. Add BodyParts to it.

Multipart mp = new MimeMultipart();

mp.addBodyPart(p1);

mp.addBodyPart(p2);

// Set Multipart as the message's content

msg.setContent(mp);

}

// Set a single part html content.

// Sending data of any type is similar.

public static void setHTMLContent(Message msg) throws MessagingException {

String html = "" +<o:p></o:p></p> <p style="font-family: georgia;" class="MsoPlainText">msg.getSubject() +<o:p></o:p></p> <p style="font-family: georgia;" class="MsoPlainText">"

" +

msg.getSubject() +

"

This is a test of sending an HTML e-mail" +

" through Java.";

// HTMLDataSource is an inner class

msg.setDataHandler(new DataHandler(new HTMLDataSource(html)));

}

/*

* Inner class to act as a JAF datasource to send HTML e-mail content

*/

static class HTMLDataSource implements DataSource {

private String html;

public HTMLDataSource(String htmlString) {

html = htmlString;

}

// Return html string in an InputStream.

// A new stream must be returned each time.

public InputStream getInputStream() throws IOException {

if (html == null) throw new IOException("Null HTML");

return new ByteArrayInputStream(html.getBytes());

}

public OutputStream getOutputStream() throws IOException {

throw new IOException("This DataHandler cannot write HTML");

}

public String getContentType() {

return "text/html";

}

public String getName() {

return "JAF text/html dataSource to send e-mail only";

}

}

} //End of class