001// --------------------------------------------------------------------------------
002// Copyright 2002-2024 Echo Three, LLC
003//
004// Licensed under the Apache License, Version 2.0 (the "License");
005// you may not use this file except in compliance with the License.
006// You may obtain a copy of the License at
007//
008//     http://www.apache.org/licenses/LICENSE-2.0
009//
010// Unless required by applicable law or agreed to in writing, software
011// distributed under the License is distributed on an "AS IS" BASIS,
012// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013// See the License for the specific language governing permissions and
014// limitations under the License.
015// --------------------------------------------------------------------------------
016
017package com.echothree.util.server.persistence;
018
019import com.echothree.model.control.core.common.ComponentVendors;
020import com.echothree.model.control.core.common.EntityTypes;
021import com.echothree.model.control.security.common.SecurityRoleGroups;
022import com.echothree.model.control.security.common.SecurityRoles;
023import com.echothree.model.control.security.server.logic.SecurityRoleLogic;
024import com.echothree.model.control.sequence.common.SequenceTypes;
025import com.echothree.model.control.sequence.server.logic.SequenceGeneratorLogic;
026import com.echothree.model.control.warehouse.server.control.WarehouseControl;
027import com.echothree.model.data.communication.common.pk.CommunicationEventPK;
028import com.echothree.model.data.communication.server.factory.CommunicationEventFactory;
029import com.echothree.model.data.contactlist.common.pk.PartyContactListPK;
030import com.echothree.model.data.contactlist.server.factory.PartyContactListFactory;
031import com.echothree.model.data.core.common.pk.ComponentVendorPK;
032import com.echothree.model.data.core.common.pk.EntityTypePK;
033import com.echothree.model.data.core.common.pk.MimeTypePK;
034import com.echothree.model.data.core.server.entity.EntityInstance;
035import com.echothree.model.data.core.server.factory.ComponentVendorFactory;
036import com.echothree.model.data.core.server.factory.EntityTypeFactory;
037import com.echothree.model.data.core.server.factory.MimeTypeFactory;
038import com.echothree.model.data.forum.common.pk.ForumGroupPK;
039import com.echothree.model.data.forum.common.pk.ForumMessagePK;
040import com.echothree.model.data.forum.common.pk.ForumPK;
041import com.echothree.model.data.forum.common.pk.ForumThreadPK;
042import com.echothree.model.data.forum.server.factory.ForumFactory;
043import com.echothree.model.data.forum.server.factory.ForumGroupFactory;
044import com.echothree.model.data.forum.server.factory.ForumMessageFactory;
045import com.echothree.model.data.forum.server.factory.ForumThreadFactory;
046import com.echothree.model.data.item.common.pk.ItemDescriptionPK;
047import com.echothree.model.data.item.common.pk.ItemPK;
048import com.echothree.model.data.item.server.factory.ItemDescriptionFactory;
049import com.echothree.model.data.item.server.factory.ItemFactory;
050import com.echothree.model.data.party.server.entity.Party;
051import com.echothree.model.data.subscription.common.pk.SubscriptionPK;
052import com.echothree.model.data.subscription.server.factory.SubscriptionFactory;
053import com.echothree.model.data.training.common.pk.PartyTrainingClassPK;
054import com.echothree.model.data.training.common.pk.TrainingClassPK;
055import com.echothree.model.data.training.server.factory.PartyTrainingClassFactory;
056import com.echothree.model.data.training.server.factory.TrainingClassFactory;
057import com.echothree.model.data.vendor.common.pk.VendorItemPK;
058import com.echothree.model.data.vendor.server.factory.VendorItemFactory;
059import com.echothree.model.data.warehouse.common.pk.LocationPK;
060import com.echothree.model.data.warehouse.server.factory.LocationFactory;
061import com.echothree.util.common.persistence.EntityNames;
062import com.echothree.util.common.persistence.Names;
063import com.echothree.util.common.persistence.Targets;
064import com.echothree.util.common.transfer.MapWrapper;
065import com.echothree.util.server.persistence.translator.ComponentVendorTranslator;
066import com.echothree.util.server.persistence.translator.EntityInstanceAndNames;
067import com.echothree.util.server.persistence.translator.EntityInstanceTranslator;
068import com.echothree.util.server.persistence.translator.InvoiceNameTranslator;
069import com.echothree.util.server.persistence.translator.OrderNameTranslator;
070import com.echothree.util.server.persistence.translator.PartyNameTranslator;
071import com.echothree.util.server.persistence.translator.SequenceTypeTranslator;
072import java.util.Collections;
073import java.util.HashMap;
074import java.util.Map;
075
076public class EntityNamesUtils {
077    
078    private EntityNamesUtils() {
079        super();
080    }
081    
082    private static class EntityNamesUtilsHolder {
083        static EntityNamesUtils instance = new EntityNamesUtils();
084    }
085    
086    public static EntityNamesUtils getInstance() {
087        return EntityNamesUtilsHolder.instance;
088    }
089
090    private final static Map<String, ComponentVendorTranslator> componentVendorTranslators = new HashMap<>();
091
092    public static void addComponentVendorTranslator(String componentVendorName, ComponentVendorTranslator componentVendorTranslator) {
093        componentVendorTranslators.put(componentVendorName, componentVendorTranslator);
094    }
095
096    static {
097        Map<String, EntityInstanceTranslator> nameTranslators = new HashMap<>(16);
098
099        nameTranslators.put(EntityTypes.Invoice.name(), new InvoiceNameTranslator());
100        nameTranslators.put(EntityTypes.Order.name(), new OrderNameTranslator());
101        nameTranslators.put(EntityTypes.Party.name(), new PartyNameTranslator());
102
103        nameTranslators.put(EntityTypes.Item.name(), (final EntityInstance entityInstance) -> {
104            var itemDetail = ItemFactory.getInstance().getEntityFromPK(EntityPermission.READ_ONLY,
105                    new ItemPK(entityInstance.getEntityUniqueId())).getLastDetail();
106            var names = new MapWrapper<String>(1);
107
108            names.put(Names.ItemName.name(), itemDetail.getItemName());
109
110            return new EntityNames(Targets.Item.name(), names);
111        });
112
113        nameTranslators.put(EntityTypes.ItemDescription.name(), (final EntityInstance entityInstance) -> {
114            var itemDescriptionDetail = ItemDescriptionFactory.getInstance().getEntityFromPK(EntityPermission.READ_ONLY,
115                    new ItemDescriptionPK(entityInstance.getEntityUniqueId())).getLastDetail();
116            var names = new MapWrapper<String>(3);
117
118            names.put(Names.ItemDescriptionTypeName.name(), itemDescriptionDetail.getItemDescriptionType().getLastDetail().getItemDescriptionTypeName());
119            names.put(Names.ItemName.name(), itemDescriptionDetail.getItem().getLastDetail().getItemName());
120            names.put(Names.LanguageIsoName.name(), itemDescriptionDetail.getLanguage().getLanguageIsoName());
121
122            return new EntityNames(Targets.ItemDescription.name(), names);
123        });
124
125        nameTranslators.put(EntityTypes.ForumGroup.name(), (final EntityInstance entityInstance) -> {
126            var forumGroupDetail = ForumGroupFactory.getInstance().getEntityFromPK(EntityPermission.READ_ONLY,
127                    new ForumGroupPK(entityInstance.getEntityUniqueId())).getLastDetail();
128            var names = new MapWrapper<String>(1);
129
130            names.put(Names.ForumGroupName.name(), forumGroupDetail.getForumGroupName());
131
132            return new EntityNames(Targets.ForumGroup.name(), names);
133        });
134
135        nameTranslators.put(EntityTypes.Forum.name(), (final EntityInstance entityInstance) -> {
136            var forumDetail = ForumFactory.getInstance().getEntityFromPK(EntityPermission.READ_ONLY,
137                    new ForumPK(entityInstance.getEntityUniqueId())).getLastDetail();
138            var names = new MapWrapper<String>(1);
139
140            names.put(Names.ForumName.name(), forumDetail.getForumName());
141
142            return new EntityNames(Targets.Forum.name(), names);
143        });
144
145        nameTranslators.put(EntityTypes.ForumMessage.name(), (final EntityInstance entityInstance) -> {
146            var forumMessageDetail = ForumMessageFactory.getInstance().getEntityFromPK(EntityPermission.READ_ONLY,
147                    new ForumMessagePK(entityInstance.getEntityUniqueId())).getLastDetail();
148            var names = new MapWrapper<String>(1);
149
150            names.put(Names.ForumMessageName.name(), forumMessageDetail.getForumMessageName());
151
152            return new EntityNames(Targets.ForumMessage.name(), names);
153        });
154
155        nameTranslators.put(EntityTypes.ForumThread.name(), (final EntityInstance entityInstance) -> {
156            var forumThreadDetail = ForumThreadFactory.getInstance().getEntityFromPK(EntityPermission.READ_ONLY,
157                    new ForumThreadPK(entityInstance.getEntityUniqueId())).getLastDetail();
158            var names = new MapWrapper<String>(1);
159
160            names.put(Names.ForumThreadName.name(), forumThreadDetail.getForumThreadName());
161
162            return new EntityNames(Targets.ForumThread.name(), names);
163        });
164
165        nameTranslators.put(EntityTypes.TrainingClass.name(), (final EntityInstance entityInstance) -> {
166            var trainingClassDetail = TrainingClassFactory.getInstance().getEntityFromPK(EntityPermission.READ_ONLY,
167                    new TrainingClassPK(entityInstance.getEntityUniqueId())).getLastDetail();
168            var names = new MapWrapper<String>(1);
169
170            names.put(Names.TrainingClassName.name(), trainingClassDetail.getTrainingClassName());
171
172            return new EntityNames(Targets.TrainingClass.name(), names);
173        });
174
175        nameTranslators.put(EntityTypes.PartyTrainingClass.name(), (final EntityInstance entityInstance) -> {
176            var partyTrainingClassDetail = PartyTrainingClassFactory.getInstance().getEntityFromPK(EntityPermission.READ_ONLY,
177                    new PartyTrainingClassPK(entityInstance.getEntityUniqueId())).getLastDetail();
178            var names = new MapWrapper<String>(1);
179
180            names.put(Names.PartyTrainingClassName.name(), partyTrainingClassDetail.getPartyTrainingClassName());
181
182            return new EntityNames(Targets.PartyTrainingClass.name(), names);
183        });
184
185        nameTranslators.put(EntityTypes.CommunicationEvent.name(), (final EntityInstance entityInstance) -> {
186            var communicationEventDetail = CommunicationEventFactory.getInstance().getEntityFromPK(EntityPermission.READ_ONLY,
187                    new CommunicationEventPK(entityInstance.getEntityUniqueId())).getLastDetail();
188            var names = new MapWrapper<String>(1);
189
190            names.put(Names.CommunicationEventName.name(), communicationEventDetail.getCommunicationEventName());
191
192            return new EntityNames(Targets.CommunicationEvent.name(), names);
193        });
194
195        nameTranslators.put(EntityTypes.VendorItem.name(), (final EntityInstance entityInstance) -> {
196            var vendorItemDetail = VendorItemFactory.getInstance().getEntityFromPK(EntityPermission.READ_ONLY,
197                    new VendorItemPK(entityInstance.getEntityUniqueId())).getLastDetail();
198            var names = new MapWrapper<String>(2);
199
200            names.put(Names.VendorItemName.name(), vendorItemDetail.getVendorItemName());
201            names.put(Names.PartyName.name(), vendorItemDetail.getVendorParty().getLastDetail().getPartyName());
202
203            return new EntityNames(Targets.VendorItem.name(), names);
204        });
205
206        nameTranslators.put(EntityTypes.PartyContactList.name(), (final EntityInstance entityInstance) -> {
207            var partyContactListDetail = PartyContactListFactory.getInstance().getEntityFromPK(EntityPermission.READ_ONLY,
208                    new PartyContactListPK(entityInstance.getEntityUniqueId())).getLastDetail();
209            var names = new MapWrapper<String>(2);
210
211            names.put(Names.PartyName.name(), partyContactListDetail.getParty().getLastDetail().getPartyName());
212            names.put(Names.ContactListName.name(), partyContactListDetail.getContactList().getLastDetail().getContactListName());
213
214            return new EntityNames(Targets.PartyContactList.name(), names);
215        });
216
217        nameTranslators.put(EntityTypes.Subscription.name(), (final EntityInstance entityInstance) -> {
218            var subscription = SubscriptionFactory.getInstance().getEntityFromPK(EntityPermission.READ_ONLY,
219                    new SubscriptionPK(entityInstance.getEntityUniqueId()));
220            var names = new MapWrapper<String>(1);
221
222            names.put(Names.SubscriptionName.name(), subscription.getLastDetail().getSubscriptionName());
223
224            return new EntityNames(Targets.Subscription.name(), names);
225        });
226
227        nameTranslators.put(EntityTypes.MimeType.name(), (final EntityInstance entityInstance) -> {
228            var mimeType = MimeTypeFactory.getInstance().getEntityFromPK(EntityPermission.READ_ONLY,
229                    new MimeTypePK(entityInstance.getEntityUniqueId()));
230            var names = new MapWrapper<String>(1);
231
232            names.put(Names.MimeTypeName.name(), mimeType.getLastDetail().getMimeTypeName());
233
234            return new EntityNames(Targets.MimeType.name(), names);
235        });
236
237        nameTranslators.put(EntityTypes.Location.name(), (final EntityInstance entityInstance) -> {
238            var warehouseControl = Session.getModelController(WarehouseControl.class);
239            var location = LocationFactory.getInstance().getEntityFromPK(EntityPermission.READ_ONLY,
240                    new LocationPK(entityInstance.getEntityUniqueId()));
241            var names = new MapWrapper<String>(2);
242            var locationDetail = location.getLastDetail();
243
244            names.put(Names.WarehouseName.name(), warehouseControl.getWarehouse(locationDetail.getWarehouseParty()).getWarehouseName());
245            names.put(Names.LocationName.name(), locationDetail.getLocationName());
246
247            return new EntityNames(Targets.Location.name(), names);
248        });
249
250        nameTranslators.put(EntityTypes.ComponentVendor.name(), (final EntityInstance entityInstance) -> {
251            var componentVendor = ComponentVendorFactory.getInstance().getEntityFromPK(EntityPermission.READ_ONLY,
252                    new ComponentVendorPK(entityInstance.getEntityUniqueId()));
253            var names = new MapWrapper<String>(1);
254
255            names.put(Names.ComponentVendorName.name(), componentVendor.getLastDetail().getComponentVendorName());
256
257            return new EntityNames(Targets.ComponentVendor.name(), names);
258        });
259
260        nameTranslators.put(EntityTypes.EntityType.name(), (final EntityInstance entityInstance) -> {
261            var entityType = EntityTypeFactory.getInstance().getEntityFromPK(EntityPermission.READ_ONLY,
262                    new EntityTypePK(entityInstance.getEntityUniqueId()));
263            var names = new MapWrapper<String>(2);
264            var entityTypeDetail = entityType.getLastDetail();
265
266            names.put(Names.ComponentVendorName.name(), entityTypeDetail.getComponentVendor().getLastDetail().getComponentVendorName());
267            names.put(Names.EntityTypeName.name(), entityTypeDetail.getEntityTypeName());
268
269            return new EntityNames(Targets.EntityType.name(), names);
270        });
271
272        nameTranslators = Collections.unmodifiableMap(nameTranslators);
273
274        addComponentVendorTranslator(ComponentVendors.ECHO_THREE.name(), new ComponentVendorTranslator(nameTranslators));
275    }
276
277    // Entry point from the Identify UC. Permissions have already been checked at this point.
278    public EntityInstanceAndNames getEntityNames(final EntityInstance entityInstance) {
279        EntityNames result = null;
280        var entityType = entityInstance.getEntityType();
281        var componentVendor = entityType.getLastDetail().getComponentVendor();
282        var componentVendorName = componentVendor.getLastDetail().getComponentVendorName();
283
284        ComponentVendorTranslator componentVendorTranslator = componentVendorTranslators.get(componentVendorName);
285
286        if(componentVendorTranslator != null) {
287            EntityInstanceTranslator nameTranslator = componentVendorTranslator.getNameTranslators().get(entityType.getLastDetail().getEntityTypeName());
288
289            if(nameTranslator != null) {
290                result = nameTranslator.getNames(entityInstance);
291            }
292        }
293
294        return result == null ? null : new EntityInstanceAndNames(entityInstance, result);
295    }
296    
297    private final static Map<String, SequenceTypeTranslator> sequenceTypeTranslators;
298
299    private final static InvoiceNameTranslator INVOICE_NAME_TRANSLATOR = new InvoiceNameTranslator();
300    private final static OrderNameTranslator ORDER_NAME_TRANSLATOR = new OrderNameTranslator();
301    private final static PartyNameTranslator PARTY_NAME_TRANSLATOR = new PartyNameTranslator();
302
303    static {
304        var sequenceTypeTranslatorsMap = new HashMap<String, SequenceTypeTranslator>(7);
305
306        sequenceTypeTranslatorsMap.put(SequenceTypes.PURCHASE_INVOICE.name(), INVOICE_NAME_TRANSLATOR);
307        sequenceTypeTranslatorsMap.put(SequenceTypes.SALES_INVOICE.name(), INVOICE_NAME_TRANSLATOR);
308        sequenceTypeTranslatorsMap.put(SequenceTypes.PURCHASE_ORDER.name(), ORDER_NAME_TRANSLATOR);
309        sequenceTypeTranslatorsMap.put(SequenceTypes.SALES_ORDER.name(), ORDER_NAME_TRANSLATOR);
310        sequenceTypeTranslatorsMap.put(SequenceTypes.WISHLIST.name(), ORDER_NAME_TRANSLATOR);
311        sequenceTypeTranslatorsMap.put(SequenceTypes.CUSTOMER.name(), PARTY_NAME_TRANSLATOR);
312        sequenceTypeTranslatorsMap.put(SequenceTypes.EMPLOYEE.name(), PARTY_NAME_TRANSLATOR);
313        
314        sequenceTypeTranslators = Collections.unmodifiableMap(sequenceTypeTranslatorsMap);
315    }
316    
317    private EntityInstanceAndNames getEntityNames(final String sequenceTypeName, final String value,
318            final boolean includeEntityInstance) {
319        EntityInstanceAndNames result = null;
320        var sequenceTypeTranslator = sequenceTypeTranslators.get(sequenceTypeName);
321        
322        if(sequenceTypeTranslator != null) {
323            result = sequenceTypeTranslator.getNames(sequenceTypeName, value, includeEntityInstance);
324        }
325        
326        return result;
327    }
328
329    // Entry point from the Identify UC. Permissions have NOT been checked at this point.
330    public EntityInstanceAndNames getEntityNames(final Party requestingParty, final String value, final boolean includeEntityInstance) {
331        EntityInstanceAndNames result = null;
332        var sequenceType = SequenceGeneratorLogic.getInstance().identifySequenceType(value);
333
334        if(sequenceType != null) {
335            var sequenceTypeName = sequenceType.getLastDetail().getSequenceTypeName();
336            boolean hasAccess = false;
337
338            if(sequenceTypeName.equals(SequenceTypes.PURCHASE_INVOICE.name())
339                    && SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(null, requestingParty,
340                    SecurityRoleGroups.PurchaseInvoice.name(), SecurityRoles.Search.name())) {
341                hasAccess = true;
342            } else if(sequenceTypeName.equals(SequenceTypes.SALES_INVOICE.name())
343                    && SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(null, requestingParty,
344                    SecurityRoleGroups.SalesOrder.name(), SecurityRoles.Search.name())) {
345                hasAccess = true;
346            } else if(sequenceTypeName.equals(SequenceTypes.PURCHASE_ORDER.name())
347                    && SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(null, requestingParty,
348                    SecurityRoleGroups.PurchaseOrder.name(), SecurityRoles.Search.name())) {
349                hasAccess = true;
350            } else if(sequenceTypeName.equals(SequenceTypes.SALES_ORDER.name())
351                    && SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(null, requestingParty,
352                    SecurityRoleGroups.SalesOrder.name(), SecurityRoles.Search.name())) {
353                hasAccess = true;
354            } else if(sequenceTypeName.equals(SequenceTypes.WISHLIST.name())
355                    && SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(null, requestingParty,
356                    SecurityRoleGroups.Wishlist.name(), SecurityRoles.Search.name())) {
357                hasAccess = true;
358            } else if(sequenceTypeName.equals(SequenceTypes.CUSTOMER.name())
359                    && SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(null, requestingParty,
360                    SecurityRoleGroups.Customer.name(), SecurityRoles.Search.name())) {
361                hasAccess = true;
362            } else if(sequenceTypeName.equals(SequenceTypes.EMPLOYEE.name())
363                    && SecurityRoleLogic.getInstance().hasSecurityRoleUsingNames(null, requestingParty,
364                    SecurityRoleGroups.Employee.name(), SecurityRoles.Search.name())) {
365                hasAccess = true;
366            }
367
368            result = hasAccess ? getEntityNames(sequenceTypeName, value, includeEntityInstance) : null;
369        }
370        
371        return result;
372    }
373    
374}