Skip to content

Package: ProduktionsauftragsBuilder

ProduktionsauftragsBuilder

nameinstructionbranchcomplexitylinemethod
ProduktionsauftragsBuilder(ClassObjectMap)
M: 0 C: 16
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 5
100%
M: 0 C: 1
100%
addDokumentenklasse(DokumentenklasseBuilder, double)
M: 17 C: 57
77%
M: 5 C: 7
58%
M: 5 C: 2
29%
M: 3 C: 10
77%
M: 0 C: 1
100%
baue()
M: 0 C: 13
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
getBlattZahl()
M: 0 C: 9
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
getSla()
M: 13 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
hatPlatzfuerKlasse(DokumentenklasseBuilder, double)
M: 17 C: 7
29%
M: 3 C: 1
25%
M: 2 C: 1
33%
M: 1 C: 2
67%
M: 0 C: 1
100%
lambda$baue$0(Map.Entry)
M: 0 C: 9
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
lambda$getBlattZahl$1(Map.Entry)
M: 0 C: 12
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
lambda$getSla$2(DokumentenklasseBuilder)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
lambda$pruefeKompatibilitaet$3(DokumentenklasseBuilder)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
lambda$pruefeKompatibilitaet$4(List, DokumentenklassenVariable)
M: 0 C: 9
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
lambda$pruefeKompatibilitaet$5(Boolean, Boolean)
M: 0 C: 11
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
prepareKompatibitlitaetsParameter(DokumentenklasseBuilder)
M: 0 C: 14
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
pruefeKompatibilitaet(DokumentenklasseBuilder)
M: 0 C: 5
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
pruefeKompatibilitaet(DokumentenklasseBuilder, boolean)
M: 7 C: 67
91%
M: 3 C: 11
79%
M: 2 C: 6
75%
M: 3 C: 16
84%
M: 0 C: 1
100%

Coverage

1: package produktionsauftrag;
2:
3: import auftraege.ProduktionsAuftrag;
4: import auftraege.ServiceLevelAgreement;
5: import auftraege.UnpassendeKlasseException;
6: import auftraege.auftragsBildungsParameter.BeilagenArten;
7: import auftraege.auftragsBildungsParameter.FarbDruckTypMischbar;
8: import auftraege.auftragsBildungsParameter.MaxBeilagenarten;
9: import auftraege.auftragsBildungsParameter.MaxKundenauftraege;
10: import auftraege.auftragsBildungsParameter.SimplexDuplexMischbar;
11: import auftraege.auftragsBildungsParameter.abstraction.DokumentenklassenVariable;
12: import auftraege.auftragsBildungsParameter.abstraction.DokumentenklassenVariablenVisitor;
13: import auftraege.auftragsBildungsParameter.abstraction.ProduktionsauftragsParameter;
14: import auftraege.auftragsBildungsParameter.dokumentenKlassenVariablen.Beilagenart;
15: import auftraege.auftragsBildungsParameter.dokumentenKlassenVariablen.BlattAnzahl;
16: import auftraege.auftragsBildungsParameter.dokumentenKlassenVariablen.Id;
17: import auftraege.auftragsBildungsParameter.dokumentenKlassenVariablen.Kommentar;
18: import auftraege.auftragsBildungsParameter.dokumentenKlassenVariablen.ProzessModell;
19: import auftraege.auftragsBildungsParameter.dokumentenKlassenVariablen.SendungsAnzahl;
20: import auftraege.auftragsBildungsParameter.dokumentenKlassenVariablen.UnbekannteVariable;
21: import auftraege.auftragsBildungsParameter.dokumentenKlassenVariablen.UnbekannteVariablen;
22: import auftraege.versand.Kunde;
23: import maschine.faehigkeit.DruckTyp;
24: import maschine.faehigkeit.FarbDruckTyp;
25: import material.auspraegungen.Papierformat;
26: import material.kuvert.KuvertFormat;
27: import util.ClassObjectMap;
28: import util.exceptions.AlreadyExistsException;
29: import util.exceptions.SollteNichtPassierenException;
30:
31: import java.util.ArrayList;
32: import java.util.Comparator;
33: import java.util.HashMap;
34: import java.util.List;
35: import java.util.Map;
36: import java.util.Map.Entry;
37: import java.util.Optional;
38: import java.util.Set;
39: import java.util.stream.Collectors;
40: import java.util.stream.Stream;
41:
42: /**
43: * Hilfsklasse zum bauen von Produktionsaufträgen.
44: */
45: class ProduktionsauftragsBuilder {
46:
47:         private final Map<DokumentenklasseBuilder, Double> dokumentenklassen;
48:         private final ClassObjectMap<DokumentenklassenVariable> kompatibilitaetsParameter;
49:         private final ClassObjectMap<ProduktionsauftragsParameter> produktionsauftragsParameter;
50:
51:         /**
52:          * erstellt einen neuen leeren {@link ProduktionsauftragsBuilder}.
53:          *
54:          * @param produktionsauftragsParameter {@link ClassObjectMap} mit {@link ProduktionsauftragsParameter}n, die bei der Bildung von Produktionsaufträgen berücksichtigt
55:          * werden sollen.
56:          */
57:         ProduktionsauftragsBuilder(final ClassObjectMap<ProduktionsauftragsParameter> produktionsauftragsParameter) {
58:                 this.produktionsauftragsParameter = produktionsauftragsParameter;
59:                 this.dokumentenklassen = new HashMap<>();
60:                 this.kompatibilitaetsParameter = new ClassObjectMap<>();
61:         }
62:
63:         /**
64:          * Baut einen neuen {@link ProduktionsAuftrag} aus den Klassen und Parametern des {@link ProduktionsauftragsBuilder}s.
65:          *
66:          * @return ProduktionsAuftrag
67:          */
68:         ProduktionsAuftrag baue() {
69:                 return new ProduktionsAuftrag(
70:                                 this.dokumentenklassen.entrySet().stream()
71:                                                 .map((final Entry<DokumentenklasseBuilder, Double> k) -> k.getKey().baue(k.getValue()))
72:                                                 .collect(Collectors.toList()));
73:         }
74:
75:         /**
76:          * Prüft, ob die Dokumentenklasse schon in dem Produktionsauftrag vorhanden ist.
77:          *
78:          * @param klasse ist die zu überprüfende Klasse
79:          * @param faktor der Faktor unter dem das Ergebnis liegen muss
80:          * @return True, wenn die Klasse mit weniger Prozent als Faktor in dem Auftrag vorhanden ist.
81:          */
82:         private boolean hatPlatzfuerKlasse(final DokumentenklasseBuilder klasse, final double faktor) {
83:•                if (!this.dokumentenklassen.containsKey(klasse)) {
84:                         return true;
85:                 }
86:•                return (faktor - (1 - this.dokumentenklassen.get(klasse))) <= 0;
87:         }
88:
89:         /**
90:          * @return Anzahl der Blätter in dem Produktionsauftrag. Mindestens eins
91:          */
92:         Integer getBlattZahl() {
93:                 return this.dokumentenklassen.entrySet().stream()
94:                                 .mapToInt((final Entry<DokumentenklasseBuilder, Double> k) -> (int) (k.getKey().getAnzahlBlaetter() * k.getValue())).sum();
95:         }
96:
97:         /**
98:          * @return den frühesten {@link ServiceLevelAgreement} aller {@link auftraege.Dokumentenklasse}n in diesem {@link ProduktionsauftragsBuilder}. Sollte keine dieser
99:          * Dokumentenklassen ein SLA besitzen, so wird ein Maximaler SLA zurückgegeben.
100:          */
101:         public ServiceLevelAgreement getSla() {
102:                 return this.dokumentenklassen.keySet().stream()
103:                                 .min(Comparator.comparing(dokumentenklassenBuilder -> dokumentenklassenBuilder.getSla().getFrist(dokumentenklassenBuilder.getEingangszeitpunkt())))
104:                                 .map(DokumentenklasseBuilder::getSla).orElse(ServiceLevelAgreement.MAX_VALUE);
105:         }
106:
107:         /**
108:          * Fügt eine Klasse oder einen Teil der Klasse in den Produktionsauftrag ein.
109:          *
110:          * @param klasse ist die einzufügende Klasse von Dokumenten.
111:          * @param plusFaktor ist der Faktor von 0 bis 1, zu dem die Klasse in den Produktionsauftrag eingefügt werden kann.
112:          * @throws AlreadyExistsException wenn die Klasse mit mehr als 100 % in dem Auftfrag wäre.
113:          * @throws FaktorOutOfBoundsException wenn Faktor kleiner oder gleich 0.
114:          * @throws UnpassendeKlasseException wenn die eindeutigen Attribute nicht übereinstimmen.
115:          */
116:         void addDokumentenklasse(final DokumentenklasseBuilder klasse, final double plusFaktor)
117:                         throws AlreadyExistsException, FaktorOutOfBoundsException, UnpassendeKlasseException {
118:•                if (plusFaktor <= 0 || plusFaktor > 1) {
119:                         throw new FaktorOutOfBoundsException();
120:                 }
121:•                if (!this.hatPlatzfuerKlasse(klasse, plusFaktor)) {
122:                         // TODO Art: unidentified; siehe Message der AlreadyExistsException.
123:                         throw new AlreadyExistsException("Hier muss sich noch etwas sinnvolles überlegt werden.");
124:                 }
125:•                if (this.dokumentenklassen.isEmpty()) {
126:                         this.prepareKompatibitlitaetsParameter(klasse);
127:•                } else if (!this.pruefeKompatibilitaet(klasse, true)) {
128:                         throw new UnpassendeKlasseException();
129:                 }
130:
131:                 Double faktor = this.dokumentenklassen.get(klasse);
132:•                faktor = faktor == null ? plusFaktor : faktor + plusFaktor;
133:                 this.dokumentenklassen.put(klasse, faktor);
134:                 klasse.setBereitsEingeplanteBlaetter(klasse.getBereitsEingeplanteBlaetter() + (int) (klasse.getAnzahlBlaetter() * plusFaktor));
135:         }
136:
137:         private void prepareKompatibitlitaetsParameter(final DokumentenklasseBuilder klasse) {
138:                 final Set<DokumentenklassenVariable> params = klasse.getVariablen().getBySuperclass(DokumentenklassenVariable.class);
139:                 params.forEach(this.kompatibilitaetsParameter::put);
140:         }
141:
142:         /**
143:          * Prüft, ob eine Dokumentenklasse in den ProduktionsausftragsBuilder gesetzt werden kann, oder ob es aufgrund enthaltener Dokumentenklassen zu inkompatibilitäten
144:          * führt.
145:          *
146:          * @param klasse DokumentenklassenBuilder, zu welchem geprüft werden soll, ob dieser in den bestehenden Produktionsauftragbuilder hinzugefügt werden kann.
147:          * @return true, wenn noch keine Dokumentenklassen hinzugefügt wurden oder alle enthaltenen Dokumentenklassen nur Variablen besitzen, welche kompatibel zu den
148:          * Variablen des Parameter {@code klasse} sind.
149:          */
150:         boolean pruefeKompatibilitaet(final DokumentenklasseBuilder klasse) {
151:                 return this.pruefeKompatibilitaet(klasse, false);
152:         }
153:
154:         /**
155:          * Prüft, ob eine Dokumentenklasse in den ProduktionsausftragsBuilder gesetzt werden kann, oder ob es aufgrund enthaltener Dokumentenklassen zu inkompatibilitäten
156:          * führt.
157:          *
158:          * @param klasse DokumentenklassenBuilder, zu welchem geprüft werden soll, ob dieser in den bestehenden Produktionsauftragbuilder hinzugefügt werden
159:          * kann.
160:          * @param passeKompatibilitaetAn falls dieser Boolean auf <i>true</i> steht, wird davon ausgegangen, dass {@code klasse} eingefügt wird und damit die {@link
161:          * ProduktionsauftragsBuilder#kompatibilitaetsParameter} angepasst werden müssen.<br> Dies wird nun automatisiert getan, falls das
162:          * Prüfungsergebnis <i>true</i> ist.
163:          * @return true, wenn noch keine Dokumentenklassen hinzugefügt wurden oder alle enthaltenen Dokumentenklassen nur Variablen besitzen, welche kompatibel zu den
164:          * Variablen des Parameter {@code klasse} sind.
165:          */
166:         private boolean pruefeKompatibilitaet(final DokumentenklasseBuilder klasse, final boolean passeKompatibilitaetAn) {
167:•                if (this.kompatibilitaetsParameter.isEmpty()) {
168:•                        if (passeKompatibilitaetAn) {
169:                                 this.prepareKompatibitlitaetsParameter(klasse);
170:                         }
171:                         return true;
172:                 } else {
173:                         if (this.dokumentenklassen.size()
174:•                                        >= this.produktionsauftragsParameter.get(MaxKundenauftraege.class).map(MaxKundenauftraege::getValue).orElse(Integer.MAX_VALUE)) {
175:                                 return false;
176:                         }
177:                         /*
178:                          * Liste der Kommandos, welche ausgeführt werden, wenn @param passendeKompatibilitaetAn und das Prüfergebnis <i>true</i> sind.
179:                          */
180:                         final List<Runnable> after = new ArrayList<>();
181:•                        final Boolean pruefErgebnis = (klasse.getVariable(UnbekannteVariablen.class).isPresent() || this.dokumentenklassen
182:                                         .keySet()
183:                                         .stream()
184:                                         .map(d -> d.getVariable(UnbekannteVariablen.class))
185:•                                        .noneMatch(Optional::isPresent))
186:                                         && klasse.getVariablen().valueStream()
187:                                         .map(dokumentenklassenVariable -> dokumentenklassenVariable.accept(new DokumentenklassenVariablenVisitorImpl(after)))
188:•                                        .reduce(true, (current, rest) -> current && rest);
189:•                        if (pruefErgebnis) {
190:                                 after.forEach(Runnable::run);
191:                         }
192:                         return pruefErgebnis;
193:                 }
194:         }
195:
196: /**
197: * Innere Klasse, welche einen Namen bekommen hat damit Checkstyle nicht meckert.
198: * // TODO Art: unidentified; Jan oder Jeremy bitte beschreiben, was diese Klasse genau tut und evtl den Namen anpassen.
199: */
200: private class DokumentenklassenVariablenVisitorImpl implements DokumentenklassenVariablenVisitor<Boolean> {
201: private final List<Runnable> after;
202:
203: DokumentenklassenVariablenVisitorImpl(final List<Runnable> after) {
204: this.after = after;
205: }
206:
207: @Override
208: public Boolean handle(final KuvertFormat kuvertFormat) {
209: return ProduktionsauftragsBuilder.this.kompatibilitaetsParameter.get(KuvertFormat.class)
210: .map(kuvertFormat::equals)
211: .orElseGet(() -> {
212: this.after.add(() -> ProduktionsauftragsBuilder.this.kompatibilitaetsParameter.put(kuvertFormat));
213: return true;
214: });
215:
216: }
217:
218: @Override
219: public Boolean handle(final BeilagenArten beilagen) {
220: final Optional<MaxBeilagenarten> maxBeilagenarten = ProduktionsauftragsBuilder.this.produktionsauftragsParameter.get(MaxBeilagenarten.class);
221: if (!maxBeilagenarten.isPresent()) {
222: //Falls keine Begrenzung für MaxBeilagenarten existiert, dann ist auf jeden Fall Platz!
223: return true;
224: } else {
225: // ermitteln aller bereits verwendeten Beilagen durch Iteration über sämtliche bereits
226: // eingeplanten Dokumentenklassen und Aggregation ihrer BeilagenArten
227: final Set<Beilagenart> bereitsEingeplanteBeilagen = ProduktionsauftragsBuilder.this.dokumentenklassen.keySet().stream()
228: .map(d -> d.getVariablen().get(BeilagenArten.class))
229: .map(beilagenarten -> beilagenarten.orElse(BeilagenArten.EMPTY).getBeilagenarten())
230: .flatMap(Set::stream)
231: .collect(Collectors.toSet());
232:
233: //Prüfung, ob nach Hinzufügen der hinzukommenden BeilagenArten die Kapazitätsgrenze überschritten wird.
234: return Stream.concat(bereitsEingeplanteBeilagen.stream(), beilagen.getBeilagenarten().stream())
235: .distinct()
236: .count() <= maxBeilagenarten.map(MaxBeilagenarten::getBegrenzung)
237: .orElseThrow(SollteNichtPassierenException::new);
238: }
239: }
240:
241: @Override
242: public Boolean handle(final ProzessModell prozessModell) {
243: return ProduktionsauftragsBuilder.this.kompatibilitaetsParameter.get(ProzessModell.class)
244: .map(prozessModell::equals)
245: .orElseGet(() -> {
246: this.after.add(() -> ProduktionsauftragsBuilder.this.kompatibilitaetsParameter.put(prozessModell));
247: return true;
248: });
249: }
250:
251: @Override
252: public Boolean handle(final DruckTyp druckTyp) {
253: return ProduktionsauftragsBuilder.this.produktionsauftragsParameter.get(SimplexDuplexMischbar.class)
254: .isPresent() ? true
255: : ProduktionsauftragsBuilder.this.kompatibilitaetsParameter.get(DruckTyp.class)
256: .map(druckTyp::equals)
257: .orElseGet(() -> {
258: this.after.add(() -> ProduktionsauftragsBuilder.this.kompatibilitaetsParameter.put(druckTyp));
259: return true;
260: });
261: }
262:
263: @Override
264: public Boolean handle(final FarbDruckTyp farbDruckTyp) {
265: return ProduktionsauftragsBuilder.this.produktionsauftragsParameter.get(FarbDruckTypMischbar.class)
266: .isPresent() ? true
267: : ProduktionsauftragsBuilder.this.kompatibilitaetsParameter.get(FarbDruckTyp.class)
268: .map(farbDruckTyp::equals)
269: .orElseGet(() -> {
270: this.after.add(() -> ProduktionsauftragsBuilder.this.kompatibilitaetsParameter.put(farbDruckTyp));
271: return true;
272: });
273: }
274:
275: @Override
276: public Boolean handle(final ServiceLevelAgreement serviceLevelAgreement) {
277: return true;
278: }
279:
280: @Override
281: public Boolean handle(final Papierformat papierformat) {
282: //TODO Art: Work in Progress; hier muss auch noch auf die Produktionsauftragsparameter geschaut werden, welche aktuell noch nicht implementiert sind.
283: return ProduktionsauftragsBuilder.this.kompatibilitaetsParameter.get(Papierformat.class)
284: .map(papierformat::equals)
285: .orElseGet(() -> {
286: this.after.add(() -> ProduktionsauftragsBuilder.this.kompatibilitaetsParameter.put(papierformat));
287: return true;
288: });
289: }
290:
291: @Override
292: public Boolean handle(final BlattAnzahl blattAnzahl) {
293: return true;
294: }
295:
296: @Override
297: public Boolean handle(final Id id) {
298: return true;
299: }
300:
301: @Override
302: public Boolean handle(final SendungsAnzahl sendungsAnzahl) {
303: return true;
304: }
305:
306: @Override
307: public Boolean handle(final Kunde kunde) {
308: return true;
309: }
310:
311: @Override
312: public Boolean handle(final UnbekannteVariable unbekannteVariable) {
313: //TODO Art: unidentified; eigentlich sollte UnbekannteVariable auch keine DokumentenklassenVariable mehr sein,
314: //lässt sich aber zzt. nicht ohne großes Refactoring ändern vermutlich
315: throw new SollteNichtPassierenException("Alle unbekannten Variablen sollten an dieser Stelle bereits herausgefiltert worden sein.");
316: }
317:
318: @Override
319: public Boolean handle(final UnbekannteVariablen unbekannteVariablen) {
320: return ProduktionsauftragsBuilder.this.kompatibilitaetsParameter.get(UnbekannteVariablen.class)
321: .map(unbekannteVariablen::equals)
322:                  .orElse(false);
323: }
324:
325: @Override
326: public Boolean handle(final Kommentar kommentar) {
327: return true;
328: }
329: }
330: }