Thank you for your interest in contributing to platform-java! We welcome contributions from the community.
- Code of Conduct
- How to Contribute
- First-Time Contributors
- Reporting Bugs
- Suggesting Features
- Pull Request Process
- Development Setup
- Code Style
- Testing Requirements
- Commit Message Guidelines
- Developer Certificate of Origin
- License
- Getting Help
This project adheres to a Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to the project maintainers.
There are many ways to contribute to platform-java:
- Report bugs - Help us identify and fix issues
- Suggest features - Share ideas for improvements
- Write code - Submit pull requests with bug fixes or new features
- Improve documentation - Help make our docs clearer and more comprehensive
- Review pull requests - Provide feedback on open PRs
- Answer questions - Help other users in discussions and issues
New to open source or to platform-java? Welcome! Here is how to get started:
- Browse "good first issue" labels - Look for issues labeled
good first issuefor beginner-friendly tasks - Read the architecture overview - Review ARCHITECTURE.md to understand the module structure
- Set up your development environment - Follow the Development Setup section below
- Start small - Documentation improvements, test additions, and small bug fixes are great first contributions
- Ask questions - Open a GitHub Discussion if you need guidance
We value all contributions, no matter how small. Fixing a typo in documentation is just as welcome as adding a new feature.
Before creating a bug report, please check the existing issues to avoid duplicates.
When filing a bug report, please include:
- Clear title - Brief description of the problem
- Description - Detailed explanation of the issue
- Steps to reproduce - Numbered steps to recreate the bug
- Expected behavior - What you expected to happen
- Actual behavior - What actually happened
- Environment - OS, Java version, platform-java version
- Logs/Screenshots - Any relevant output or error messages
Example:
**Title**: ApplicationManager throws NPE when deploying with null descriptor
**Description**: Calling `manager.deploy(null)` causes a NullPointerException instead of throwing IllegalArgumentException.
**Steps to Reproduce**:
1. Create ApplicationManager instance
2. Call `manager.deploy(null)`
3. Observe NPE
**Expected**: Should throw IllegalArgumentException with message "descriptor cannot be null"
**Actual**: Throws NPE at line 123 of ApplicationManager.java
**Environment**:
- OS: Ubuntu 22.04
- Java: OpenJDK 21.0.1
- platform-java: 1.1
**Logs**:java.lang.NullPointerException at org.flossware.platform.core.ApplicationManager.deploy(ApplicationManager.java:123)
Feature requests are welcome! Before creating a feature request:
- Check existing issues for similar requests
- Consider if it fits the project's scope and goals
- Think about backwards compatibility
When suggesting a feature, please include:
- Use case - Why is this feature needed?
- Proposed solution - How should it work?
- Alternatives - What other approaches did you consider?
- Examples - Code examples or mockups if applicable
# Fork the repository on GitHub, then:
git clone https://github.com/YOUR-USERNAME/platform-java.git
cd platform-java
git remote add upstream https://github.com/FlossWare/platform-java.gitUse a descriptive branch name:
git checkout -b fix/issue-123-npe-in-deploy
# or
git checkout -b feature/add-jwt-authenticationBranch naming convention:
fix/issue-XXX-description- Bug fixesfeature/description- New featuresdocs/description- Documentation changesrefactor/description- Code refactoring
- Write clean, readable code
- Follow the code style guidelines
- Add tests for new functionality
- Update documentation as needed
- Keep commits focused and atomic
# Run all tests
mvn clean verify
# Check code coverage (JaCoCo enforces >=60% instruction/branch/line coverage;
# the CI quality gate targets >=93% instruction coverage)
mvn clean test jacoco:report
open target/site/jacoco/index.html
# Run quality checks
mvn checkstyle:check pmd:check spotbugs:checkAll quality gates must pass before submitting a PR.
Follow the commit message guidelines:
git add .
git commit -m "fix: resolve NPE when deploying null descriptor (#123)"git push origin fix/issue-123-npe-in-deployThen create a Pull Request on GitHub with:
- Clear title - Summarize the change
- Description - Explain what and why
- Issue reference - Link to related issue(s)
- Testing - Describe how you tested
- Screenshots - For UI changes
PR Template:
## Description
Fixes #123 - ApplicationManager now validates descriptor parameter and throws IllegalArgumentException instead of NPE.
## Changes
- Added null check in `ApplicationManager.deploy()`
- Added unit test for null descriptor
- Updated JavaDoc
## Testing
- Added `ApplicationManagerTest.testDeployNullDescriptor()`
- All existing tests pass
- Coverage: 94% (increased from 93%)
## Checklist
- [x] Tests added/updated
- [x] Documentation updated
- [x] Code follows style guidelines
- [x] All quality checks pass- Address all review comments
- Push additional commits to the same branch
- Request re-review when ready
Maintainers will squash commits when merging. Your PR title becomes the commit message, so make it clear and descriptive.
- Java 21+ - OpenJDK or Oracle JDK
- Maven 3.9+ - Build tool
- Git - Version control
# Clone the repository
git clone https://github.com/FlossWare/platform-java.git
cd platform-java
# Build all modules
mvn clean install
# Build specific module
cd platform-core
mvn clean install
# Skip tests (faster, but not recommended)
mvn clean install -DskipTests
# Run with all quality checks
mvn clean verify# Basic launcher
java -jar platform-launcher/target/platform-launcher-1.1.jar
# With REST API
java -jar platform-launcher/target/platform-launcher-1.1.jar --rest-api
# With all features
java -jar platform-launcher/target/platform-launcher-1.1.jar \
--rest-api --web-console --jmx-port 9999 --prometheus- Open project:
File → Open → Select platform-java directory - Import as Maven project
- Enable annotation processing:
Settings → Build → Compiler → Annotation Processors - Install Checkstyle plugin:
Settings → Plugins → Checkstyle-IDEA - Configure Checkstyle:
Settings → Tools → Checkstyle → Configuration File → checkstyle.xml
File → Import → Maven → Existing Maven Projects- Select
platform-javadirectory - Install Checkstyle plugin from Marketplace
- Configure:
Window → Preferences → Checkstyle → New → checkstyle.xml
- Install extensions:
- Language Support for Java
- Maven for Java
- Checkstyle for Java
- Open folder:
File → Open Folder → platform-java
We follow Google Java Style enforced by Spotless and Checkstyle:
Code is automatically formatted using Spotless with Google Java Format:
# Auto-format all code before committing
mvn spotless:apply
# Check formatting without changing files
mvn spotless:checkKey Formatting Rules:
- Indentation: 2 spaces (not tabs) - enforced by Google Java Format
- Line length: 120 characters max
- Braces: K&R style (opening brace on same line)
// Good (Google Java Style - 2 space indent)
public void myMethod() {
if (condition) {
doSomething();
}
}
// Bad - wrong indentation
public void myMethod() {
if (condition) {
doSomething();
}
}
// Bad - wrong brace style
public void myMethod()
{
if (condition)
{
doSomething();
}
}- Classes:
PascalCase(e.g.,ApplicationManager) - Methods:
camelCase(e.g.,deployApplication()) - Constants:
UPPER_SNAKE_CASE(e.g.,MAX_RETRY_COUNT) - Packages: lowercase, no underscores (e.g.,
org.flossware.platform.core)
- One class per file
- Package-private by default, public only when necessary
- Final by default for local variables and parameters
- Static imports only for constants and utility methods
- JavaDoc for all public classes and methods
- No commented-out code (use git history instead)
- Explain WHY, not WHAT - code should be self-documenting
// Good - explains why
// Retry 3 times because network may be temporarily unavailable
private static final int MAX_RETRY_COUNT = 3;
// Bad - restates the obvious
// Maximum retry count is 3
private static final int MAX_RETRY_COUNT = 3;- Don't catch generic Exception - catch specific types
- Don't swallow exceptions - log or rethrow
- Use meaningful error messages
// Good
try {
deployApplication(descriptor);
} catch (ClassNotFoundException e) {
throw new DeploymentException("Main class not found: " + descriptor.getMainClass(), e);
}
// Bad
try {
deployApplication(descriptor);
} catch (Exception e) {
// ignore
}- Use SLF4J, not System.out
- Appropriate log levels: DEBUG, INFO, WARN, ERROR
- Parameterized messages for better performance
// Good
logger.info("Deploying application: {}", appId);
// Bad
System.out.println("Deploying application: " + appId);Spotless automatically formats code to Google Java Style:
# Format all code (run before committing)
mvn spotless:apply
# Check if code is formatted correctly
mvn spotless:check
# Runs automatically during verify phase
mvn clean verifyWhat Spotless Does:
- Applies Google Java Format
- Removes unused imports
- Trims trailing whitespace
- Ensures file ends with newline
All code must pass Checkstyle validation:
# Check code style
mvn checkstyle:check
# Runs automatically during validate phase
mvn clean verifyConfiguration: checkstyle.xml (based on Google Java Style with FlossWare conventions)
Key Rules:
- No wildcard imports (
import java.util.*) - Missing
@Overrideannotations detected - Method length limit: 150 lines
- Parameter count limit: 7
- Nested block depth limits
- Javadoc required for public APIs
Common violations to avoid:
- Wildcard imports (
import java.util.*;) - Missing
@Overrideannotations - Incorrect indentation
- Line too long (>120 chars)
- Missing JavaDoc on public methods
- Build enforcement: 60% instruction, branch, and line coverage (enforced by JaCoCo in
pom.xml) - CI quality gate target: 93% instruction coverage (enforced by the CI quality-gate workflow)
- New code requirement: 80%+ coverage for all new code
- All new code must have tests
- Tests must be meaningful, not just coverage boosters
Follow the Arrange-Act-Assert pattern:
@Test
void shouldDeployApplicationSuccessfully() {
// Arrange
ApplicationManager manager = new ApplicationManager();
ApplicationDescriptor descriptor = createTestDescriptor();
// Act
manager.deploy(descriptor);
// Assert
assertEquals(ApplicationState.DEPLOYED,
manager.getApplicationContext("test-app").getState());
}All tests must be tagged as either unit or integration tests:
// Unit tests - fast, isolated, no external dependencies
@Test
@Tag("unit")
void shouldValidateDescriptorFields() { ... }
// Integration tests - involve multiple components or external systems
@Test
@Tag("integration")
void shouldDeployToRemoteRegistry() { ... }Run specific test categories:
# Run only unit tests
mvn test -Dgroups="unit"
# Run only integration tests
mvn test -Dgroups="integration"
# Run all tests
mvn testUse descriptive names following should<ExpectedBehavior>When<StateUnderTest> pattern:
@Test
@Tag("unit")
void shouldThrowExceptionWhenDescriptorIsNull() { ... }
@Test
@Tag("unit")
void shouldStartApplicationWhenInDeployedState() { ... }
@Test
@Tag("integration")
void shouldRejectDuplicateApplicationId() { ... }- One test class per production class
- Group related tests with
@Nestedclasses - Use
@BeforeEachfor common setup
class ApplicationManagerTest {
private ApplicationManager manager;
@BeforeEach
void setUp() {
manager = new ApplicationManager();
}
@Nested
class DeploymentTests {
@Test
@Tag("unit")
void shouldDeployApplication() { ... }
@Test
@Tag("unit")
void shouldRejectDuplicateId() { ... }
}
@Nested
class LifecycleTests {
@Test
@Tag("integration")
void shouldStartDeployedApplication() { ... }
}
}Use Mockito for mocking dependencies:
@ExtendWith(MockitoExtension.class)
class ApplicationManagerTest {
@Mock
private ClassLoaderFactory classLoaderFactory;
@InjectMocks
private ApplicationManager manager;
@Test
void shouldCreateIsolatedClassLoader() {
when(classLoaderFactory.createClassLoader(any()))
.thenReturn(mock(ClassLoader.class));
manager.deploy(descriptor);
verify(classLoaderFactory).createClassLoader(any());
}
}# Run all tests
mvn test
# Run specific test class
mvn test -Dtest=ApplicationManagerTest
# Run specific test method
mvn test -Dtest=ApplicationManagerTest#shouldDeployApplication
# Run tests with coverage
mvn clean test jacoco:report
# Skip tests (not recommended)
mvn install -DskipTestsWe follow the Conventional Commits specification.
IMPORTANT: Your commit messages automatically generate the CHANGELOG.md. Write clear, descriptive messages!
<type>(<scope>): <subject>
<body>
<footer>
feat: New feature (appears in "Added" section)fix: Bug fix (appears in "Fixed" section)docs: Documentation changes (appears in "Documentation" section)perf: Performance improvements (appears in "Performance" section)style: Code style (formatting, no logic change) - not in changelogrefactor: Code refactoring - not in changelogtest: Adding or updating tests - not in changelogchore: Maintenance tasks (build, dependencies) - not in changelog
The module or component affected. Recommended scopes:
api- REST APIcore- Core platformsecurity- Security frameworkconfig- Configuration systemmonitoring- Monitoring/metricscluster- Clusteringstorage- Storage pluginsregistry- Service registryui- User interface (web, swing, terminal)- Other specific modules
feat(api): add JWT authentication support
Implements JWT-based authentication for REST API endpoints.
- Add JwtAuthFilter for token validation
- Add JwtConfig for configuration
- Update REST API documentation
Closes #311
fix(core): resolve NPE in ApplicationManager.deploy()
Add null check for descriptor parameter and throw
IllegalArgumentException with descriptive message.
Fixes #123
docs(readme): update quick start guide
Add Docker deployment instructions and update
REST API examples.
perf(classloader): reduce class loading overhead
Use caching for compiled bytecode to avoid
repeated compilation during hot reload cycles.
Results: 40% faster class reload time
When pair programming or collaborating:
feat(security): implement role-based access control
Implement role-based access control (RBAC) to REST API.
Co-authored-by: Jane Doe <jane@example.com>
For commits introducing breaking changes, add ! before the colon:
feat(api)!: change REST API response format
BREAKING CHANGE: Response payload format changed from flat
to nested structure.
Migration guide available in docs/BREAKING_CHANGES.md
Commits are automatically parsed to generate CHANGELOG.md. See CHANGELOG_AUTOMATION.md for:
- How changelog generation works
- How to test locally
- Troubleshooting guide
This project uses the Developer Certificate of Origin (DCO) to ensure that contributors have the right to submit their work. By making a contribution, you certify that:
- The contribution was created in whole or in part by you and you have the right to submit it under the project's open source license; or
- The contribution is based upon previous work that, to the best of your knowledge, is covered under an appropriate open source license and you have the right to submit that work with modifications; or
- The contribution was provided directly to you by some other person who certified the above and you have not modified it.
You acknowledge this by including a Signed-off-by line in your commit messages:
Signed-off-by: Your Name <your.email@example.com>
You can add this automatically using git commit -s.
Note: This project does not require a Contributor License Agreement (CLA). The DCO is sufficient.
By contributing to platform-java, you agree that your contributions will be licensed under the GNU General Public License v3.0.
All contributed code must:
- Include appropriate copyright headers
- Be your original work or properly attributed
- Not violate any third-party licenses
If you have questions or need guidance, here are the best ways to reach out:
- Documentation: See README.md, ARCHITECTURE.md, and docs/
- Issues: Browse existing issues or open a new one
- Discussions: Ask questions in GitHub Discussions
- Code of Conduct concerns: Contact the project maintainer at scot.floess@gmail.com
Thank you for contributing to platform-java!