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.model.control.core.server.logic;
018
019import com.echothree.control.user.core.common.spec.EntityRefSpec;
020import com.echothree.control.user.core.common.spec.GuidSpec;
021import com.echothree.control.user.core.common.spec.KeySpec;
022import com.echothree.control.user.core.common.spec.UlidSpec;
023import com.echothree.control.user.core.common.spec.UniversalEntitySpec;
024import com.echothree.model.control.core.common.ComponentVendors;
025import com.echothree.model.control.core.common.EventTypes;
026import com.echothree.model.control.core.common.exception.InvalidComponentVendorException;
027import com.echothree.model.control.core.common.exception.InvalidEntityTypeException;
028import com.echothree.model.control.core.common.exception.InvalidParameterCountException;
029import com.echothree.model.control.core.common.exception.UnknownEntityRefException;
030import com.echothree.model.control.core.common.exception.UnknownGuidException;
031import com.echothree.model.control.core.common.exception.UnknownKeyException;
032import com.echothree.model.control.core.common.exception.UnknownUlidException;
033import com.echothree.model.control.core.server.control.CoreControl;
034import com.echothree.model.control.core.server.database.EntityInstancesByEntityTypeWithNullDeletedTimeQuery;
035import com.echothree.model.data.core.server.entity.EntityInstance;
036import com.echothree.model.data.core.server.entity.EntityTime;
037import com.echothree.model.data.core.server.entity.EntityType;
038import com.echothree.model.data.core.server.entity.EntityTypeDetail;
039import com.echothree.model.data.core.server.factory.EntityInstanceFactory;
040import com.echothree.util.common.message.ExecutionErrors;
041import com.echothree.util.common.persistence.BasePK;
042import com.echothree.util.server.control.BaseLogic;
043import com.echothree.util.server.message.ExecutionErrorAccumulator;
044import com.echothree.util.server.persistence.EntityIdGenerator;
045import com.echothree.util.server.persistence.EntityPermission;
046import com.echothree.util.server.persistence.Session;
047
048public class EntityInstanceLogic
049        extends BaseLogic {
050
051    private EntityInstanceLogic() {
052        super();
053    }
054
055    private static class EntityInstanceLogicHolder {
056        static EntityInstanceLogic instance = new EntityInstanceLogic();
057    }
058
059    public static EntityInstanceLogic getInstance() {
060        return EntityInstanceLogicHolder.instance;
061    }
062
063    public EntityInstance createEntityInstance(final ExecutionErrorAccumulator eea, final EntityType entityType,
064            final BasePK createdBy) {
065        var entityTypeDetail = entityType.getLastDetail();
066        var componentVendorName = entityTypeDetail.getComponentVendor().getLastDetail().getComponentVendorName();
067        EntityInstance entityInstance = null;
068
069        if(!ComponentVendors.ECHO_THREE.name().equals(componentVendorName)) {
070            var coreControl = Session.getModelController(CoreControl.class);
071            var entityTypeName = entityTypeDetail.getEntityTypeName();
072            var entityIdGenerator = new EntityIdGenerator(componentVendorName, entityTypeName, 1); // TODO
073            var entityId = entityIdGenerator.getNextEntityId();
074            var basePK = new BasePK(componentVendorName, entityTypeName, entityId);
075            var event = coreControl.sendEvent(basePK, EventTypes.CREATE, null, null, createdBy);
076
077            entityInstance = event.getEntityInstance();
078        } else {
079            handleExecutionError(InvalidComponentVendorException.class, eea, ExecutionErrors.InvalidComponentVendor.name(), componentVendorName);
080        }
081
082        return entityInstance;
083    }
084
085    private EntityInstance checkEntityTimeForDeletion(CoreControl coreControl, EntityInstance entityInstance) {
086        // If the EntityInstance is null, then it is already going to indicate it has been deleted, otherwise...
087        if(entityInstance != null) {
088            EntityTime entityTime = coreControl.getEntityTime(entityInstance);
089
090            // If the EntityTime is null, then we're not going to find a DeletedTime, which means it must exist...
091            if(entityTime != null) {
092                // Check the DeletedTime...
093                if(entityTime.getDeletedTime() != null) {
094                    // It's been deleted.
095                    entityInstance = null;
096                }
097            }
098        }
099        
100        return entityInstance;
101    }
102    
103    public EntityInstance getEntityInstanceByEntityRef(final ExecutionErrorAccumulator eea, final String entityRef) {
104        var coreControl = Session.getModelController(CoreControl.class);
105        EntityInstance entityInstance = checkEntityTimeForDeletion(coreControl, coreControl.getEntityInstanceByEntityRef(entityRef));
106        
107        if(entityInstance == null) {
108            handleExecutionError(UnknownEntityRefException.class, eea, ExecutionErrors.UnknownEntityRef.name(), entityRef);
109        }
110
111        return entityInstance;
112    }
113
114    public EntityInstance getEntityInstanceByEntityRef(final ExecutionErrorAccumulator eea, final EntityRefSpec spec) {
115        return getEntityInstanceByEntityRef(eea, spec.getEntityRef());
116    }
117    
118    public EntityInstance getEntityInstanceByKey(final ExecutionErrorAccumulator eea, final String key) {
119        var coreControl = Session.getModelController(CoreControl.class);
120        EntityInstance entityInstance = checkEntityTimeForDeletion(coreControl, coreControl.getEntityInstanceByKey(key));
121
122        if(entityInstance == null) {
123            handleExecutionError(UnknownKeyException.class, eea, ExecutionErrors.UnknownKey.name(), key);
124        }
125
126        return entityInstance;
127    }
128
129    public EntityInstance getEntityInstanceByKey(final ExecutionErrorAccumulator eea, final KeySpec spec) {
130        return getEntityInstanceByKey(eea, spec.getKey());
131    }
132    
133    public EntityInstance getEntityInstanceByGuid(final ExecutionErrorAccumulator eea, final String guid) {
134        var coreControl = Session.getModelController(CoreControl.class);
135        EntityInstance entityInstance = checkEntityTimeForDeletion(coreControl, coreControl.getEntityInstanceByGuid(guid));
136
137        if(entityInstance == null) {
138            handleExecutionError(UnknownGuidException.class, eea, ExecutionErrors.UnknownGuid.name(), guid);
139        }
140
141        return entityInstance;
142    }
143
144    public EntityInstance getEntityInstanceByUlid(final ExecutionErrorAccumulator eea, final String ulid) {
145        var coreControl = Session.getModelController(CoreControl.class);
146        EntityInstance entityInstance = checkEntityTimeForDeletion(coreControl, coreControl.getEntityInstanceByUlid(ulid));
147
148        if(entityInstance == null) {
149            handleExecutionError(UnknownUlidException.class, eea, ExecutionErrors.UnknownUlid.name(), ulid);
150        }
151
152        return entityInstance;
153    }
154
155    public EntityInstance getEntityInstanceByGuid(final ExecutionErrorAccumulator eea, final GuidSpec spec) {
156        return getEntityInstanceByGuid(eea, spec.getGuid());
157    }
158    
159    public EntityInstance getEntityInstanceByUlid(final ExecutionErrorAccumulator eea, final UlidSpec spec) {
160        return getEntityInstanceByUlid(eea, spec.getUlid());
161    }
162    
163    public EntityInstance getEntityInstance(final ExecutionErrorAccumulator eea, final String entityRef, final String key,
164            final String guid, final String ulid, final String componentVendorName, final String... entityTypeNames) {
165        var parameterCount = countPossibleEntitySpecs(entityRef, key, guid, ulid);
166        EntityInstance entityInstance = null;
167        
168        if(parameterCount == 1) {
169            if(entityRef != null) {
170                entityInstance = getEntityInstanceByEntityRef(eea, entityRef);
171            } else if(key != null) {
172                entityInstance = getEntityInstanceByKey(eea, key);
173            } else if(guid != null) {
174                entityInstance = getEntityInstanceByGuid(eea, guid);
175            } else if(ulid != null) {
176                entityInstance = getEntityInstanceByUlid(eea, ulid);
177            }
178        } else {
179            handleExecutionError(InvalidParameterCountException.class, eea, ExecutionErrors.InvalidParameterCount.name());
180        }
181        
182        if((eea == null || !eea.hasExecutionErrors()) && componentVendorName != null && entityTypeNames.length > 0) {
183            EntityTypeDetail entityTypeDetail = entityInstance.getEntityType().getLastDetail();
184            String foundComponentVendorName = entityTypeDetail.getComponentVendor().getLastDetail().getComponentVendorName();
185            String foundEntityTypeName = entityTypeDetail.getEntityTypeName();
186            boolean found = false;
187            
188            if(foundComponentVendorName.equals(componentVendorName)) {
189                for(var entityTypeName : entityTypeNames) {
190                    if(entityTypeName.equals(foundEntityTypeName)) {
191                        found = true;
192                        break;
193                    }
194                }
195            }
196            
197            if(!found) {
198                handleExecutionError(InvalidEntityTypeException.class, eea, ExecutionErrors.InvalidEntityType.name(), foundComponentVendorName, foundEntityTypeName);
199                entityInstance = null;
200            }
201        }
202        
203        return entityInstance;
204    }
205    
206    public EntityInstance getEntityInstance(final ExecutionErrorAccumulator eea, final EntityRefSpec entityRefSpec, final KeySpec keySpec,
207            final GuidSpec guidSpec, final UlidSpec ulidSpec, final String componentVendorName, final String... entityTypeNames) {
208        return getEntityInstance(eea, entityRefSpec.getEntityRef(), keySpec.getKey(), guidSpec.getGuid(), ulidSpec.getUlid(),
209                componentVendorName, entityTypeNames);
210    }
211    
212    public EntityInstance getEntityInstance(final ExecutionErrorAccumulator eea, final UniversalEntitySpec universalEntitySpec) {
213        return getEntityInstance(eea, universalEntitySpec.getEntityRef(), universalEntitySpec.getKey(),
214                universalEntitySpec.getGuid(), universalEntitySpec.getUlid(), null);
215    }
216    
217    public EntityInstance getEntityInstance(final ExecutionErrorAccumulator eea, final UniversalEntitySpec universalEntitySpec,
218            final String componentVendorName, final String... entityTypeNames) {
219        return getEntityInstance(eea, universalEntitySpec.getEntityRef(), universalEntitySpec.getKey(),
220                universalEntitySpec.getGuid(), universalEntitySpec.getUlid(), componentVendorName, entityTypeNames);
221    }
222    
223    public int countPossibleEntitySpecs(final String entityRef, final String key, final String guid, final String ulid) {
224        return (entityRef == null ? 0 : 1) + (key == null ? 0 : 1) + (guid == null ? 0 : 1) + (ulid == null ? 0 : 1);
225    }
226    
227    public int countPossibleEntitySpecs(final EntityRefSpec entityRefSpec, final KeySpec keySpec, final GuidSpec guidSpec,
228            final UlidSpec ulidSpec) {
229        return countPossibleEntitySpecs(entityRefSpec == null ? null : entityRefSpec.getEntityRef(),
230                keySpec == null ? null : keySpec.getKey(), guidSpec == null ? null : guidSpec.getGuid(),
231                ulidSpec == null ? null : ulidSpec.getUlid());
232    }
233    
234    public int countPossibleEntitySpecs(final UniversalEntitySpec universalEntitySpec) {
235        return universalEntitySpec == null ? 0 : countPossibleEntitySpecs(universalEntitySpec.getEntityRef(),
236                universalEntitySpec.getKey(), universalEntitySpec.getGuid(), universalEntitySpec.getUlid());
237    }
238    
239    public String getEntityRefFromEntityInstance(EntityInstance entityInstance) {
240        var entityTypeDetail = entityInstance.getEntityType().getLastDetail();
241        var componentVendorDetail = entityTypeDetail.getComponentVendor().getLastDetail();
242        
243        return new StringBuilder(componentVendorDetail.getComponentVendorName()).append('.')
244                .append(entityTypeDetail.getEntityTypeName()).append('.')
245                .append(entityInstance.getEntityUniqueId()).toString();
246    }
247
248    public void deleteEntityInstance(final ExecutionErrorAccumulator eea, final EntityInstance entityInstance, final BasePK deletedBy) {
249        var componentVendorName = entityInstance.getEntityType().getLastDetail().getComponentVendor().getLastDetail().getComponentVendorName();
250
251        if(!ComponentVendors.ECHO_THREE.name().equals(componentVendorName)) {
252            var coreControl = Session.getModelController(CoreControl.class);
253
254            coreControl.deleteEntityInstance(entityInstance, deletedBy);
255        } else {
256            handleExecutionError(InvalidComponentVendorException.class, eea, ExecutionErrors.InvalidComponentVendor.name(), componentVendorName);
257        }
258    }
259
260    public void removeEntityInstance(final ExecutionErrorAccumulator eea, final EntityInstance entityInstance) {
261        var componentVendorName = entityInstance.getEntityType().getLastDetail().getComponentVendor().getLastDetail().getComponentVendorName();
262
263        if(!ComponentVendors.ECHO_THREE.name().equals(componentVendorName)) {
264            var coreControl = Session.getModelController(CoreControl.class);
265
266            coreControl.removeEntityInstance(entityInstance);
267        } else {
268            handleExecutionError(InvalidComponentVendorException.class, eea, ExecutionErrors.InvalidComponentVendor.name(), componentVendorName);
269        }
270    }
271
272}