Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enforcing layered architecture in Java

Given a software system written in Java consisting of three layers, A -> B -> C, i.e. layer A uses layer B and B uses layer C.

I want to make sure that a class of one layer only has access only to classes of the same layer or its direct dependency, i.e. B should be able to access C but not A. Also A should be able to access B but not C.

Is there an easy way to enforce such a restriction? Ideally I want eclipse to complain at once if one tries to access a class of the wrong layer.

The software currently uses maven. Therefore I tried to put A, B, and C into different maven modules and to declare dependencies properly. This works fine to prevent B to access A, but does not prevent A to access C.

Next I tried to exclude C from the dependency to B. This now also prevents access from A to C. However now I am no longer able to use copy-dependencies to collect all transitive dependencies needed for run time.

Is there a good way that allows me a clean separation of layers, but also allows me to collect all needed runtime dependencies?

like image 463
michas Avatar asked Jan 16 '15 13:01

michas


People also ask

What is layered architecture in Java?

In a layered architecture, layers are stacked on top of one of another: Componentes from one layer are only allowed to communicate with the components from the layer one level below: The most common type of Layered Architecture is a 3-Layered Architecture.

What is 4 layered architecture?

The four layers of four-tier architecture are presentation layer (PL), data service layer (DSL), business logic layer (BLL), and data access layer (DAL).

What are the types of layered architecture?

N-layer, hexagonal and onion are all layered architecture styles, but each one features its own unique spin on distributed design and modular development. It's possible that the greatest insult you could hurl at an application architecture is to call it monolithic.

What is layered architecture example?

Gmail is divided into at least three layers, every one of them has a mission, and they exist separately to handle different processes at different levels. It is an excellent example of layered architecture.


2 Answers

in maven you can use the maven-macker-plugin as following example:

<build>
    <plugins>
        <plugin>
            <groupId>de.andrena.tools.macker</groupId>
            <artifactId>macker-maven-plugin</artifactId>
            <version>1.0.2</version>
            <executions>
                <execution>
                    <phase>compile</phase>
                    <goals>
                        <goal>macker</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

and here is an example macker-rules.xml example file: (put it on the same level as your pom.xml)

<?xml version="1.0"?>
<macker>

    <ruleset name="Layering rules">
        <var name="base" value="org.example" />

        <pattern name="appl" class="${base}.**" />
        <pattern name="common" class="${base}.common.**" />
        <pattern name="persistence" class="${base}.persistence.**" />
        <pattern name="business" class="${base}.business.**" />
        <pattern name="web" class="${base}.web.**" />

        <!-- =============================================================== -->
        <!-- Common -->
        <!-- =============================================================== -->
        <access-rule>
            <message>zugriff auf common; von überall gestattet</message>
            <deny>
                <to pattern="common" />
                <allow>
                    <from>
                        <include pattern="appl" />
                    </from>
                </allow>
            </deny>
        </access-rule>

        <!-- =============================================================== -->
        <!-- Persistence -->
        <!-- =============================================================== -->
        <access-rule>
            <message>zugriff auf persistence; von web und business gestattet</message>
            <deny>
                <to pattern="persistence" />
                <allow>
                    <from>
                        <include pattern="persistence" />
                        <include pattern="web" />
                        <include pattern="business" />
                    </from>
                </allow>
            </deny>
        </access-rule>

        <!-- =============================================================== -->
        <!-- Business -->
        <!-- =============================================================== -->
        <access-rule>
            <message>zugriff auf business; nur von web gestattet</message>
            <deny>
                <to pattern="business" />
                <allow>
                    <from>
                        <include pattern="business" />
                        <include pattern="web" />
                    </from>
                </allow>
            </deny>
        </access-rule>

        <!-- =============================================================== -->
        <!-- Web -->
        <!-- =============================================================== -->
        <access-rule>
            <message>zugriff auf web; von nirgends gestattet</message>
            <deny>
                <to pattern="web" />
                <allow>
                    <from>
                        <include pattern="web" />
                    </from>
                </allow>
            </deny>
        </access-rule>

        <!-- =============================================================== -->
        <!-- Libraries gebunden an ein spezifisches Modul -->
        <!-- =============================================================== -->
        <access-rule>
            <message>nur in web erlaubt</message>
            <deny>
                <to>
                    <include class="javax.faces.**" />
                    <include class="javax.servlet.**" />
                    <include class="javax.ws.*" />
                    <include class="javax.enterprise.*" />
                </to>
                <allow>
                    <from pattern="web" />
                </allow>
            </deny>
        </access-rule>

        <access-rule>
            <message>nur in business und persistence erlaubt</message>
            <deny>
                <to>
                    <include class="javax.ejb.**" />
                    <include class="java.sql.**" />
                    <include class="javax.sql.**" />
                    <include class="javax.persistence.**" />
                </to>
                <allow>
                    <from>
                        <include pattern="business" />
                        <include pattern="persistence" />
                    </from>
                </allow>
            </deny>
        </access-rule>

    </ruleset>

</macker>

and in a simple multi module maven project simply put the macker-rules.xml in a central place and point to the directory where it is stored. then you need to configure the plugin in your parent pom.xml

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>de.andrena.tools.macker</groupId>
                <artifactId>macker-maven-plugin</artifactId>
                <version>1.0.2</version>
                <executions>
                    <execution>
                        <phase>compile</phase>
                        <goals>
                            <goal>macker</goal>
                        </goals>
                        <configuration>
                            <rulesDirectory>../</rulesDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </pluginManagement>
</build>
like image 102
StefanHeimberg Avatar answered Sep 24 '22 01:09

StefanHeimberg


If I was you I would do the following steps:

  • For each layer create two modules. One for interfaces another for the implementation.
  • Do a proper maven dependency avoiding transitive dependencies.
  • Install Sonargraph-Architect plugin in eclipse. It will let you to configure your layer rules.
like image 37
spino Avatar answered Sep 25 '22 01:09

spino