Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
P
program
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Iterations
Merge Requests
0
Merge Requests
0
Requirements
Requirements
List
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Test Cases
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Operations
Operations
Incidents
Environments
Packages & Registries
Packages & Registries
Package Registry
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issue
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
BA-EA Smells
program
Commits
233a41e6
Commit
233a41e6
authored
Jul 20, 2019
by
Johannes Salentin
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'release/1.0'
parents
f0e6a95a
592aff0b
Pipeline
#163002
passed with stages
in 2 minutes and 3 seconds
Changes
37
Pipelines
1
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
37 changed files
with
7448 additions
and
4481 deletions
+7448
-4481
CentralModel.xml
CentralModel.xml
+5679
-4289
SmellExample.xml
SmellExample.xml
+1103
-0
Test.xml
Test.xml
+0
-78
pom.xml
pom.xml
+2
-2
src/main/java/de/example/main/EASmellDetector.java
src/main/java/de/example/main/EASmellDetector.java
+13
-0
src/main/java/de/example/main/ModelAdapter.java
src/main/java/de/example/main/ModelAdapter.java
+100
-13
src/main/java/de/example/smells/AmbiguousViewpoint.java
src/main/java/de/example/smells/AmbiguousViewpoint.java
+21
-0
src/main/java/de/example/smells/ChattyService.java
src/main/java/de/example/smells/ChattyService.java
+37
-0
src/main/java/de/example/smells/Constants.java
src/main/java/de/example/smells/Constants.java
+16
-4
src/main/java/de/example/smells/CyclicDependency.java
src/main/java/de/example/smells/CyclicDependency.java
+16
-12
src/main/java/de/example/smells/DataService.java
src/main/java/de/example/smells/DataService.java
+35
-0
src/main/java/de/example/smells/DeadComponent.java
src/main/java/de/example/smells/DeadComponent.java
+22
-5
src/main/java/de/example/smells/DenseStructure.java
src/main/java/de/example/smells/DenseStructure.java
+25
-2
src/main/java/de/example/smells/Detector.java
src/main/java/de/example/smells/Detector.java
+16
-0
src/main/java/de/example/smells/Documentation.java
src/main/java/de/example/smells/Documentation.java
+1
-2
src/main/java/de/example/smells/Duplication.java
src/main/java/de/example/smells/Duplication.java
+9
-7
src/main/java/de/example/smells/EASmell.java
src/main/java/de/example/smells/EASmell.java
+2
-1
src/main/java/de/example/smells/HubLikeModularization.java
src/main/java/de/example/smells/HubLikeModularization.java
+17
-4
src/main/java/de/example/smells/LazyComponent.java
src/main/java/de/example/smells/LazyComponent.java
+33
-0
src/main/java/de/example/smells/MessageChain.java
src/main/java/de/example/smells/MessageChain.java
+66
-0
src/main/java/de/example/smells/SharedPersistency.java
src/main/java/de/example/smells/SharedPersistency.java
+3
-2
src/main/java/de/example/smells/StrictLayersViolation.java
src/main/java/de/example/smells/StrictLayersViolation.java
+5
-4
src/main/java/de/example/smells/WeakenedModularity.java
src/main/java/de/example/smells/WeakenedModularity.java
+19
-12
src/test/java/de/example/smells/TestAmbiguousViewpoint.java
src/test/java/de/example/smells/TestAmbiguousViewpoint.java
+29
-0
src/test/java/de/example/smells/TestChattyService.java
src/test/java/de/example/smells/TestChattyService.java
+27
-0
src/test/java/de/example/smells/TestCyclicDependency.java
src/test/java/de/example/smells/TestCyclicDependency.java
+8
-5
src/test/java/de/example/smells/TestDataService.java
src/test/java/de/example/smells/TestDataService.java
+27
-0
src/test/java/de/example/smells/TestDeadComponent.java
src/test/java/de/example/smells/TestDeadComponent.java
+8
-5
src/test/java/de/example/smells/TestDenseStructure.java
src/test/java/de/example/smells/TestDenseStructure.java
+8
-5
src/test/java/de/example/smells/TestDocumentation.java
src/test/java/de/example/smells/TestDocumentation.java
+8
-5
src/test/java/de/example/smells/TestDuplication.java
src/test/java/de/example/smells/TestDuplication.java
+8
-5
src/test/java/de/example/smells/TestHubLikeModularization.java
...est/java/de/example/smells/TestHubLikeModularization.java
+8
-5
src/test/java/de/example/smells/TestLazyComponent.java
src/test/java/de/example/smells/TestLazyComponent.java
+27
-0
src/test/java/de/example/smells/TestMessageChain.java
src/test/java/de/example/smells/TestMessageChain.java
+27
-0
src/test/java/de/example/smells/TestSharedPersistency.java
src/test/java/de/example/smells/TestSharedPersistency.java
+7
-4
src/test/java/de/example/smells/TestStrictLayersViolation.java
...est/java/de/example/smells/TestStrictLayersViolation.java
+8
-5
src/test/java/de/example/smells/TestWeakenedModularity.java
src/test/java/de/example/smells/TestWeakenedModularity.java
+8
-5
No files found.
CentralModel.xml
View file @
233a41e6
This diff is collapsed.
Click to expand it.
SmellExample.xml
0 → 100644
View file @
233a41e6
This diff is collapsed.
Click to expand it.
Test.xml
deleted
100644 → 0
View file @
f0e6a95a
<?xml version="1.0" encoding="UTF-8"?>
<model
xmlns=
"http://www.opengroup.org/xsd/archimate/3.0/"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://www.opengroup.org/xsd/archimate/3.0/ http://www.opengroup.org/xsd/archimate/3.0/archimate3_Diagram.xsd"
identifier=
"id-825fc864-cf1b-44ee-9aae-e18b93b010f5"
>
<name
xml:lang=
"de"
>
Test
</name>
<elements>
<element
identifier=
"id-c75917ca-5c20-4fc1-be7d-8756eef684b0"
xsi:type=
"BusinessService"
>
<name
xml:lang=
"de"
>
S1
</name>
</element>
<element
identifier=
"id-435bc94c-32fc-48fb-8677-e2ff74eb32c8"
xsi:type=
"BusinessService"
>
<name
xml:lang=
"de"
>
S2
</name>
</element>
<element
identifier=
"id-ab882019-9db1-4442-800f-c106b05d143c"
xsi:type=
"BusinessService"
>
<name
xml:lang=
"de"
>
S3
</name>
</element>
</elements>
<relationships>
<relationship
identifier=
"id-db86487d-18d5-44ad-93ab-6033c0483e44"
source=
"id-c75917ca-5c20-4fc1-be7d-8756eef684b0"
target=
"id-435bc94c-32fc-48fb-8677-e2ff74eb32c8"
xsi:type=
"Serving"
/>
<relationship
identifier=
"id-85ef5ebb-0cf3-4a6f-ae84-96db26374e54"
source=
"id-435bc94c-32fc-48fb-8677-e2ff74eb32c8"
target=
"id-ab882019-9db1-4442-800f-c106b05d143c"
xsi:type=
"Serving"
/>
<relationship
identifier=
"id-3331e143-5efe-47af-b2a1-90334bcb736e"
source=
"id-ab882019-9db1-4442-800f-c106b05d143c"
target=
"id-c75917ca-5c20-4fc1-be7d-8756eef684b0"
xsi:type=
"Serving"
/>
</relationships>
<views>
<diagrams>
<view
identifier=
"id-605923ee-be74-40a4-9526-199a71bffa5c"
xsi:type=
"Diagram"
>
<name
xml:lang=
"de"
>
Default View
</name>
<node
identifier=
"id-47063029-f542-4d37-b937-0a4bc8aa66aa"
elementRef=
"id-c75917ca-5c20-4fc1-be7d-8756eef684b0"
xsi:type=
"Element"
x=
"120"
y=
"72"
w=
"505"
h=
"181"
>
<style>
<fillColor
r=
"255"
g=
"255"
b=
"181"
a=
"100"
/>
<lineColor
r=
"92"
g=
"92"
b=
"92"
/>
<font
name=
"Segoe UI"
size=
"9"
>
<color
r=
"0"
g=
"0"
b=
"0"
/>
</font>
</style>
</node>
<node
identifier=
"id-63ae4155-ef68-4f1b-9d0e-5ecf07b22f26"
elementRef=
"id-435bc94c-32fc-48fb-8677-e2ff74eb32c8"
xsi:type=
"Element"
x=
"720"
y=
"132"
w=
"241"
h=
"121"
>
<style>
<fillColor
r=
"255"
g=
"255"
b=
"181"
a=
"100"
/>
<lineColor
r=
"92"
g=
"92"
b=
"92"
/>
<font
name=
"Segoe UI"
size=
"9"
>
<color
r=
"0"
g=
"0"
b=
"0"
/>
</font>
</style>
</node>
<node
identifier=
"id-546e1ea3-d887-4aca-b2d0-a83fa3243196"
elementRef=
"id-ab882019-9db1-4442-800f-c106b05d143c"
xsi:type=
"Element"
x=
"180"
y=
"372"
w=
"385"
h=
"121"
>
<style>
<fillColor
r=
"255"
g=
"255"
b=
"181"
a=
"100"
/>
<lineColor
r=
"92"
g=
"92"
b=
"92"
/>
<font
name=
"Segoe UI"
size=
"9"
>
<color
r=
"0"
g=
"0"
b=
"0"
/>
</font>
</style>
</node>
<connection
identifier=
"id-d08a21eb-2c62-4f01-8a4c-9b060b0fa6b2"
relationshipRef=
"id-db86487d-18d5-44ad-93ab-6033c0483e44"
xsi:type=
"Relationship"
source=
"id-47063029-f542-4d37-b937-0a4bc8aa66aa"
target=
"id-63ae4155-ef68-4f1b-9d0e-5ecf07b22f26"
>
<style>
<lineColor
r=
"0"
g=
"0"
b=
"0"
/>
<font
name=
"Segoe UI"
size=
"9"
>
<color
r=
"0"
g=
"0"
b=
"0"
/>
</font>
</style>
</connection>
<connection
identifier=
"id-8f89b5a3-712a-4f5b-841e-beee2f87b868"
relationshipRef=
"id-85ef5ebb-0cf3-4a6f-ae84-96db26374e54"
xsi:type=
"Relationship"
source=
"id-63ae4155-ef68-4f1b-9d0e-5ecf07b22f26"
target=
"id-546e1ea3-d887-4aca-b2d0-a83fa3243196"
>
<style>
<lineColor
r=
"0"
g=
"0"
b=
"0"
/>
<font
name=
"Segoe UI"
size=
"9"
>
<color
r=
"0"
g=
"0"
b=
"0"
/>
</font>
</style>
</connection>
<connection
identifier=
"id-ee353188-d6cd-4122-aec9-738467d1d1fd"
relationshipRef=
"id-3331e143-5efe-47af-b2a1-90334bcb736e"
xsi:type=
"Relationship"
source=
"id-546e1ea3-d887-4aca-b2d0-a83fa3243196"
target=
"id-47063029-f542-4d37-b937-0a4bc8aa66aa"
>
<style>
<lineColor
r=
"0"
g=
"0"
b=
"0"
/>
<font
name=
"Segoe UI"
size=
"9"
>
<color
r=
"0"
g=
"0"
b=
"0"
/>
</font>
</style>
</connection>
</view>
</diagrams>
</views>
</model>
pom.xml
View file @
233a41e6
...
...
@@ -6,7 +6,7 @@
<groupId>
de.example.main
</groupId>
<artifactId>
EASmellsDetection
</artifactId>
<version>
1.0
-SNAPSHOT
</version>
<version>
1.0
</version>
<name>
EA Smell Detection
</name>
<properties>
...
...
@@ -36,7 +36,7 @@
<directory>
${basedir}
</directory>
<includes>
<include>
CentralModel.xml
</include>
<include>
Test
.xml
</include>
<include>
SmellExample
.xml
</include>
<include>
archimate3_Diagram.xsd
</include>
<include>
archimate3_View.xsd
</include>
<include>
archimate3_Model.xsd
</include>
...
...
src/main/java/de/example/main/EASmellDetector.java
View file @
233a41e6
...
...
@@ -5,22 +5,33 @@ import de.example.smells.*;
import
java.util.ArrayList
;
import
java.util.List
;
/**
* main class that manages the different detectors
*/
public
class
EASmellDetector
{
public
static
void
main
(
String
[]
args
)
{
// parsing of input xml to this ModelAdapter
ModelAdapter
model
=
new
ModelAdapter
(
args
[
0
],
args
.
length
==
2
?
args
[
1
]
:
null
);
Detector
.
setModel
(
model
);
// register detectors
List
<
Detector
>
detectors
=
new
ArrayList
<>();
detectors
.
add
(
new
AmbiguousViewpoint
());
detectors
.
add
(
new
ChattyService
());
detectors
.
add
(
new
CyclicDependency
());
detectors
.
add
(
new
DataService
());
detectors
.
add
(
new
DeadComponent
());
detectors
.
add
(
new
DenseStructure
());
detectors
.
add
(
new
Documentation
());
detectors
.
add
(
new
Duplication
());
detectors
.
add
(
new
HubLikeModularization
());
detectors
.
add
(
new
LazyComponent
());
detectors
.
add
(
new
MessageChain
());
detectors
.
add
(
new
SharedPersistency
());
detectors
.
add
(
new
StrictLayersViolation
());
detectors
.
add
(
new
WeakenedModularity
());
// detect each smell
System
.
out
.
print
(
"\n"
);
long
startTotalTime
=
System
.
nanoTime
();
for
(
Detector
detector
:
detectors
)
{
...
...
@@ -33,6 +44,8 @@ public class EASmellDetector {
System
.
out
.
println
(
"Finished detection of "
+
detector
.
getSmellName
()
+
" in "
+
time
+
" ("
+
memory
+
")\n"
);
}
// print total result
System
.
out
.
println
(
"The following "
+
Detector
.
getSmells
().
size
()
+
" smells were detected:"
);
printSmells
(
Detector
.
getSmells
());
String
totalTime
=
calculateTimeConsumption
(
startTotalTime
);
...
...
src/main/java/de/example/main/ModelAdapter.java
View file @
233a41e6
...
...
@@ -5,11 +5,12 @@ import org.xml.sax.SAXException;
import
javax.xml.bind.JAXBException
;
import
javax.xml.namespace.QName
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.*
;
import
java.util.stream.Collectors
;
/**
* adapt the more complex generated model and extend the functionality
*/
public
class
ModelAdapter
{
private
static
ModelType
model
;
...
...
@@ -33,7 +34,8 @@ public class ModelAdapter {
}
public
ElementType
getElementByIdentifier
(
String
id
)
{
List
<
ElementType
>
elements
=
model
.
getElements
().
getElement
().
stream
().
filter
(
e
->
e
.
getIdentifier
().
equals
(
id
)).
collect
(
Collectors
.
toList
());
List
<
ElementType
>
elements
=
model
.
getElements
().
getElement
().
stream
().
filter
(
e
->
e
.
getIdentifier
().
equals
(
id
))
.
collect
(
Collectors
.
toList
());
if
(
elements
.
isEmpty
())
{
return
null
;
}
else
{
...
...
@@ -142,22 +144,107 @@ public class ModelAdapter {
}
public
List
<
ElementType
>
getElementsInLayer
(
String
layer
)
{
List
<
OrganizationType
>
l
=
model
.
getOrganizations
().
get
(
0
).
getItem
().
stream
().
filter
(
e
->
e
.
getLabelGroup
().
get
(
0
).
getValue
().
toLowerCase
().
contains
(
layer
.
toLowerCase
())).
collect
(
Collectors
.
toList
());
if
(
l
.
isEmpty
())
{
return
new
ArrayList
<>(
);
// fallback if organizations is not specified in xml: use the alternative
if
(
model
.
getOrganizations
()
.
isEmpty
())
{
return
getElementsInLayerAlternative
(
layer
);
}
else
{
l
=
l
.
get
(
0
).
getItem
();
List
<
ElementType
>
res
=
new
ArrayList
<>();
for
(
OrganizationType
element
:
l
)
{
ElementType
tmp
=
(
ElementType
)
element
.
getIdentifierRef
();
res
.
add
(
tmp
);
List
<
OrganizationType
>
l
=
model
.
getOrganizations
().
get
(
0
).
getItem
().
stream
().
filter
(
e
->
e
.
getLabelGroup
().
get
(
0
).
getValue
().
toLowerCase
().
contains
(
layer
.
toLowerCase
())).
collect
(
Collectors
.
toList
());
if
(
l
.
isEmpty
())
{
return
new
ArrayList
<>();
}
else
if
(
l
.
get
(
0
).
getItem
().
isEmpty
())
{
return
new
ArrayList
<>();
}
else
{
l
=
l
.
get
(
0
).
getItem
();
List
<
ElementType
>
res
=
new
ArrayList
<>();
for
(
OrganizationType
element
:
l
)
{
ElementType
tmp
=
(
ElementType
)
element
.
getIdentifierRef
();
res
.
add
(
tmp
);
}
return
res
;
}
}
}
public
List
<
ElementType
>
getElementsOfType
(
String
[]
types
)
{
return
getElements
().
stream
().
filter
(
e
->
{
for
(
String
type
:
types
)
{
if
(
e
.
getClass
().
getSimpleName
().
equals
(
type
))
{
return
true
;
}
}
return
res
;
return
false
;
}).
collect
(
Collectors
.
toList
());
}
// alternative for getElementsInLayer when organizations is not specified in xml
public
List
<
ElementType
>
getElementsInLayerAlternative
(
String
layer
)
{
String
[]
types
;
switch
(
layer
)
{
case
"Business"
:
types
=
new
String
[]{
"BusinessActor"
,
"BusinessRole"
,
"BusinessCollaboration"
,
"BusinessInterface"
,
"BusinessProcess"
,
"BusinessFunction"
,
"BusinessInteraction"
,
"BusinessEvent"
,
"BusinessService"
,
"BusinessObject"
,
"Contract"
,
"Representation"
,
"Product"
};
break
;
case
"Application"
:
types
=
new
String
[]{
"ApplicationComponent"
,
"ApplicationCollaboration"
,
"ApplicationInterface"
,
"ApplicationFunction"
,
"ApplicationInteraction"
,
"ApplicationProcess"
,
"ApplicationEvent"
,
"ApplicationService"
,
"DataObject"
};
break
;
case
"Technology"
:
types
=
new
String
[]{
"Node"
,
"Device"
,
"SystemSoftware"
,
"TechnologyCollaboration"
,
"TechnologyInterface"
,
"Path"
,
"CommunicationNetwork"
,
"TechnologyFunction"
,
"TechnologyProcess"
,
"TechnologyInteraction"
,
"TechnologyEvent"
,
"TechnologyService"
,
"Artifact"
,
"Equipment"
,
"Facility"
,
"DistributionNetwork"
,
"Material"
};
break
;
default
:
types
=
new
String
[]{};
}
return
getElementsOfType
(
types
);
}
public
List
<
Diagram
>
getViews
()
{
return
model
.
getViews
().
getDiagrams
().
getView
();
}
// a cluster is in one layer and is related with structural relations to each other
public
Set
<
ElementType
>
getCluster
(
ElementType
element
)
{
Set
<
ElementType
>
elementAsSet
=
new
HashSet
<>();
elementAsSet
.
add
(
element
);
List
<
ElementType
>
businessElements
=
getElementsInLayer
(
"Business"
);
if
(
businessElements
.
contains
(
element
))
{
return
getCluster
(
elementAsSet
,
businessElements
);
}
else
{
List
<
ElementType
>
applicationElements
=
getElementsInLayer
(
"Application"
);
if
(
applicationElements
.
contains
(
element
))
{
return
getCluster
(
elementAsSet
,
applicationElements
);
}
else
{
List
<
ElementType
>
technologyElements
=
getElementsInLayer
(
"Technology"
);
if
(
technologyElements
.
contains
(
element
))
{
return
getCluster
(
elementAsSet
,
technologyElements
);
}
return
elementAsSet
;
}
}
}
private
Set
<
ElementType
>
getCluster
(
Set
<
ElementType
>
elements
,
List
<
ElementType
>
elementsInSameLayer
)
{
Set
<
ElementType
>
res
=
new
HashSet
<>(
elements
);
String
[]
structuralRelationsOut
=
{
"Aggregation"
,
"Realization"
,
"Composition"
};
String
[]
structuralRelationsIn
=
{
"Assignment"
};
for
(
ElementType
element
:
elements
)
{
Set
<
ElementType
>
children
=
new
HashSet
<>(
getReferencedElementsOf
(
element
,
structuralRelationsOut
));
children
.
addAll
(
getElementsWithReferenceTo
(
element
,
structuralRelationsIn
));
children
=
children
.
stream
().
filter
(
elementsInSameLayer:
:
contains
).
collect
(
Collectors
.
toSet
());
if
(!
children
.
isEmpty
())
{
res
.
addAll
(
getCluster
(
children
,
elementsInSameLayer
));
}
}
return
res
;
}
public
boolean
isNotStructural
(
RelationshipType
relationship
)
{
String
type
=
relationship
.
getClass
().
getSimpleName
();
return
!
type
.
contains
(
"Realization"
)
&&
!
type
.
contains
(
"Assignment"
)
&&
!
type
.
contains
(
"Aggregation"
)
&&
!
type
.
contains
(
"Composition"
);
}
}
src/main/java/de/example/smells/AmbiguousViewpoint.java
0 → 100644
View file @
233a41e6
package
de.example.smells
;
import
de.example.model.Diagram
;
import
java.util.List
;
public
class
AmbiguousViewpoint
extends
Detector
{
public
AmbiguousViewpoint
()
{
super
(
"Ambiguous Viewpoint"
);
}
public
List
<
EASmell
>
detect
()
{
for
(
Diagram
view
:
model
.
getViews
())
{
if
(
view
.
getViewpoint
()
==
null
)
{
addToSmells
(
new
EASmell
(
getSmellName
(),
null
,
" at the View \""
+
view
.
getNameGroup
().
get
(
0
).
getValue
()
+
"\" ("
+
view
.
getIdentifier
()
+
")"
));
}
}
return
result
;
}
}
src/main/java/de/example/smells/ChattyService.java
0 → 100644
View file @
233a41e6
package
de.example.smells
;
import
de.example.model.ElementType
;
import
de.example.model.RelationshipType
;
import
java.util.List
;
import
java.util.stream.Collectors
;
import
static
de
.
example
.
smells
.
Constants
.
MAX_CHATTY_SERVICE_RELATIONS
;
public
class
ChattyService
extends
Detector
{
public
ChattyService
()
{
super
(
"Chatty Service"
);
}
public
List
<
EASmell
>
detect
()
{
List
<
ElementType
>
serviceElements
=
model
.
getElements
().
stream
().
filter
(
e
->
e
.
getClass
().
getSimpleName
().
contains
(
"Service"
)).
collect
(
Collectors
.
toList
());
for
(
ElementType
serviceElement
:
serviceElements
)
{
int
relationCount
=
0
;
for
(
RelationshipType
relationship
:
model
.
getRelationships
())
{
if
(
model
.
isNotStructural
(
relationship
))
{
ElementType
source
=
(
ElementType
)
relationship
.
getSource
();
ElementType
target
=
(
ElementType
)
relationship
.
getTarget
();
if
(
serviceElements
.
contains
(
source
)
&&
serviceElements
.
contains
(
target
)
&&
(
serviceElement
.
equals
(
source
)
||
serviceElement
.
equals
(
target
)))
{
relationCount
++;
}
}
}
if
(
relationCount
>
MAX_CHATTY_SERVICE_RELATIONS
)
{
addToSmells
(
new
EASmell
(
getSmellName
(),
serviceElement
,
" with "
+
relationCount
+
" related services"
));
}
}
return
result
;
}
}
src/main/java/de/example/smells/Constants.java
View file @
233a41e6
...
...
@@ -2,15 +2,27 @@ package de.example.smells;
class
Constants
{
static
final
double
MAX_AVG_DEGREE
=
2
;
// Chatty Service
static
final
int
MAX_CHATTY_SERVICE_RELATIONS
=
4
;
// Dense Structure
static
final
double
MAX_AVG_DEGREE
=
1.75
;
// Documentation
static
final
int
MAX_DOCUMENTATION_LENGTH
=
256
;
static
final
int
DUPLICATED_WORDS
=
2
;
// Duplication
static
final
double
DUPLICATED_WORDS_RATIO
=
0.75
;
// Hub-like Modularization
static
final
int
LARGE_FAN_IN
=
7
;
static
final
int
LARGE_FAN_OUT
=
7
;
static
final
int
LARGE_FAN_IN
=
10
;
static
final
int
LARGE_FAN_OUT
=
10
;
// Message Chain
static
final
int
MAX_SERVICE_CHAIN_LENGTH
=
4
;
// Weakened Modularity
static
final
int
MIN_INTERNAL_RELATIONS
=
3
;
static
final
double
MODULARITY_RATIO
=
1
;
}
src/main/java/de/example/smells/CyclicDependency.java
View file @
233a41e6
...
...
@@ -13,8 +13,7 @@ public class CyclicDependency extends Detector {
}
public
List
<
EASmell
>
detect
()
{
List
<
ElementType
>
elements
=
model
.
getElements
();
for
(
ElementType
element
:
elements
)
{
for
(
ElementType
element
:
model
.
getElements
())
{
detectCyclicDependency
(
element
);
}
return
result
;
...
...
@@ -22,18 +21,23 @@ public class CyclicDependency extends Detector {
private
void
detectCyclicDependency
(
ElementType
element
)
{
int
currentSize
=
0
;
Set
<
ElementType
>
re
ferenced
Elements
=
new
HashSet
<>(
model
.
getReferencedElementsOf
(
element
));
while
(
referencedElements
.
size
()
>
currentSize
)
{
currentSize
=
referencedElements
.
size
();
Set
<
ElementType
>
additionalElements
=
new
HashSet
<>();
for
(
ElementType
e
:
referencedElements
)
{
additionalElements
.
addAll
(
model
.
getReferencedElementsOf
(
e
))
;
Set
<
ElementType
>
re
achable
Elements
=
new
HashSet
<>(
model
.
getReferencedElementsOf
(
element
));
// while new elements were reached
while
(
reachableElements
.
size
()
>
currentSize
)
{
if
(
reachableElements
.
contains
(
element
))
{
addToSmells
(
new
EASmell
(
getSmellName
(),
element
));
break
;
}
referencedElements
.
addAll
(
additionalElements
);
currentSize
=
reachableElements
.
size
();
reachableElements
.
addAll
(
getAdditionalElements
(
reachableElements
));
}
if
(
referencedElements
.
contains
(
element
))
{
EASmell
cd
=
new
EASmell
(
getSmellName
(),
element
);
addToSmells
(
cd
);
}
private
Set
<
ElementType
>
getAdditionalElements
(
Set
<
ElementType
>
reachableElements
)
{
Set
<
ElementType
>
additionalElements
=
new
HashSet
<>();
for
(
ElementType
e
:
reachableElements
)
{
additionalElements
.
addAll
(
model
.
getReferencedElementsOf
(
e
));
}
return
additionalElements
;
}
}
src/main/java/de/example/smells/DataService.java
0 → 100644
View file @
233a41e6
package
de.example.smells
;
import
de.example.model.ElementType
;
import
java.util.List
;
import
java.util.stream.Collectors
;
public
class
DataService
extends
Detector
{
public
DataService
()
{
super
(
"Data Service"
);
}
public
List
<
EASmell
>
detect
()
{
List
<
ElementType
>
serviceElements
=
model
.
getElements
().
stream
().
filter
(
e
->
e
.
getClass
().
getSimpleName
().
contains
(
"Service"
)).
collect
(
Collectors
.
toList
());
List
<
ElementType
>
dataElements
=
model
.
getElementsOfType
(
new
String
[]{
"BusinessObject"
,
"DataObject"
,
"SystemSoftware"
});
for
(
ElementType
serviceElement
:
serviceElements
)
{
List
<
ElementType
>
referencedElements
=
model
.
getReferencedElementsOf
(
serviceElement
);
if
(!
referencedElements
.
isEmpty
())
{
boolean
onlyDataReferences
=
true
;
for
(
ElementType
referencedElement
:
referencedElements
)
{
if
(!
dataElements
.
contains
(
referencedElement
))
{
onlyDataReferences
=
false
;
break
;
}
}
if
(
onlyDataReferences
)
{
addToSmells
(
new
EASmell
(
getSmellName
(),
serviceElement
));
}
}
}
return
result
;
}
}
src/main/java/de/example/smells/DeadComponent.java
View file @
233a41e6
package
de.example.smells
;
import
de.example.model.ElementType
;
import
de.example.model.RelationshipType
;
import
java.util.List
;
import
java.util.Set
;
public
class
DeadComponent
extends
Detector
{
...
...
@@ -11,12 +13,27 @@ public class DeadComponent extends Detector {
}
public
List
<
EASmell
>
detect
()
{
List
<
ElementType
>
elements
=
model
.
getElements
();
for
(
ElementType
element
:
elements
)
{
if
(
model
.
getReferencedElementsOf
(
element
).
isEmpty
()
&&
model
.
getElementsWithReferenceTo
(
element
).
isEmpty
())
{
addToSmells
(
new
EASmell
(
getSmellName
(),
element
));
}
for
(
ElementType
element
:
model
.
getElements
())
{
detectDeadComponent
(
element
);
}
return
result
;
}
private
void
detectDeadComponent
(
ElementType
element
)
{
Set
<
ElementType
>
cluster
=
model
.
getCluster
(
element
);
boolean
used
=
false
;
for
(
RelationshipType
relationship
:
model
.
getRelationships
())
{
ElementType
target
=
(
ElementType
)
relationship
.
getTarget
();
ElementType
source
=
(
ElementType
)
relationship
.
getSource
();
// relationship to element outside the cluster -> so it is used
if
((
cluster
.
contains
(
source
)
&&
!
cluster
.
contains
(
target
))
||
(
cluster
.
contains
(
target
)
&&
!
cluster
.
contains
(
source
)))
{
used
=
true
;
break
;
}
}
if
(!
used
)
{
addToSmells
(
new
EASmell
(
getSmellName
(),
element
));
}
}
}
src/main/java/de/example/smells/DenseStructure.java
View file @
233a41e6
package
de.example.smells
;
import
de.example.model.ElementType
;
import
de.example.model.RelationshipType
;
import
java.util.List
;
import
java.util.Set
;
import
static
de
.
example
.
smells
.
Constants
.
MAX_AVG_DEGREE
;
...
...
@@ -11,12 +15,31 @@ public class DenseStructure extends Detector {
}
public
List
<
EASmell
>
detect
()
{
overallDenseStructure
();
for
(
ElementType
element
:
model
.
getElements
())
{
Set
<
ElementType
>
cluster
=
model
.
getCluster
(
element
);
double
e
=
0
;
for
(
RelationshipType
relationship
:
model
.
getRelationships
())
{
ElementType
target
=
(
ElementType
)
relationship
.
getTarget
();
ElementType
source
=
(
ElementType
)
relationship
.
getSource
();
if
(
cluster
.
contains
(
source
)
&&
cluster
.
contains
(
target
))
{
e
++;
}
}
double
avgDegree
=
e
/
cluster
.
size
();
if
(
avgDegree
>
MAX_AVG_DEGREE
)
{
addToSmells
(
new
EASmell
(
"Dense Structure"
,
element
,
" with average degree of "
+
avgDegree
));
}
}
return
result
;
}
private
void
overallDenseStructure
()
{
double
v
=
model
.
getElements
().
size
();
double
e
=
model
.
getRelationships
().
size
();
double
avgDegree
=
e
/
(
v
/* * (v - 1)*/
);
if
(
avgDegree
>
MAX_AVG_DEGREE
)
{
addToSmells
(
new
EASmell
(
"Dense Structure"
,
null
,
" with average degree of "
+
avgDegree
));
addToSmells
(
new
EASmell
(
"
Overall
Dense Structure"
,
null
,
" with average degree of "
+
avgDegree
));
}
return
result
;
}
}
src/main/java/de/example/smells/Detector.java
View file @
233a41e6
...
...
@@ -5,14 +5,20 @@ import de.example.main.ModelAdapter;
import
java.util.ArrayList
;
import
java.util.List
;
/**
* A Detector is responsible for the detection of one particular smell
*/
public
abstract
class
Detector
{
static
ModelAdapter
model
;
// detected smells of all different detectors
static
List
<
EASmell
>
smells
;
// detected smells of this detector [can be returned by detect()]
List
<
EASmell
>
result
;
private
String
smellName
;
Detector
()
{
smells
=
new
ArrayList
<>();
result
=
new
ArrayList
<>();
}
Detector
(
String
name
)
{
...
...
@@ -33,11 +39,21 @@ public abstract class Detector {
return
smellName
;
}
/**
* Adds the smell to both smell lists