/** * Can be used to perform a null check for the given field and value. * <p> * This is internally used to check all properties which must not be null * ({@link sirius.search.properties.Property#isNullAllowed()}). If a field accepts a <tt>null</tt> value but * still must be field, this method can be called in {@link #beforeSaveChecks()}. * * @param previousError Can be used to signal that an error was already found. In this case the given exception * will be returned as result even if the value was <tt>null</tt>. In most cases this * parameter will be <tt>null</tt>. * @param property the field to check * @param value the value to check. If the value is <tt>null</tt> an error will be generated. * @return an error if either the given <tt>previousError</tt> was non null or if the given value was <tt>null</tt> */ @Nullable protected HandledException checkNullability(@Nullable HandledException previousError, @Nonnull Property property, @Nullable Object value) { if (Strings.isEmpty(value)) { UserContext.setFieldError(property.getName(), null); if (previousError == null) { return Exceptions.createHandled() .withNLSKey("Entity.fieldMustBeFilled") .set("field", property.getFieldTitle()) .handle(); } } return previousError; }
private void fillField(Object obj, Map<String, String> values, Field innerField) { if (innerField.isAnnotationPresent(Transient.class) || Modifier.isStatic(innerField.getModifiers())) { return; } try { if (values.containsKey(innerField.getName())) { innerField.setAccessible(true); if (innerField.getType().equals(Map.class) || innerField.getType().equals(List.class)) { innerField.set(obj, values.get(innerField.getName())); } else { innerField.set(obj, NLS.parseMachineString(innerField.getType(), values.get(innerField.getName()))); } } } catch (Exception e) { Exceptions.handle() .error(e) .to(IndexAccess.LOG) .withSystemErrorMessage("Cannot load POJO field %s of %s: %s (%s)", innerField.getName(), toString()) .handle(); } } }
this.queryString = detectLogging(query); if (query.length() > MAX_QUERY_LENGTH) { throw Exceptions.createHandled().withNLSKey("Query.queryTooLong").handle();
/** * Completely wipes the given index. * * @param name the name of the index. The index prefix of the current system will be added automatically */ public void deleteIndex(String name) { try { DeleteIndexResponse res = getClient().admin() .indices() .prepareDelete(schema.getIndexName(name)) .execute() .get(10, TimeUnit.SECONDS); if (!res.isAcknowledged()) { throw Exceptions.handle() .to(LOG) .withSystemErrorMessage("Cannot delete index: %s", schema.getIndexName(name)) .handle(); } } catch (Exception e) { throw Exceptions.handle() .to(LOG) .error(e) .withSystemErrorMessage("Cannot delete index: %s - %s (%s)", schema.getIndexName(name)) .handle(); } }
protected void onDeleteReject(Object e) { BaseEntity<?> referenceInstance = (BaseEntity<?>) getDescriptor().getReferenceInstance(); long count = referenceInstance.getMapper() .select(referenceInstance.getClass()) .eq(nameAsMapping, ((BaseEntity<?>) e).getId()) .count(); if (count == 1) { throw Exceptions.createHandled() .withNLSKey("BaseEntityRefProperty.cannotDeleteEntityWithChild") .set("field", getLabel()) .set("type", getReferencedDescriptor().getLabel()) .set("source", getDescriptor().getLabel()) .handle(); } if (count > 1) { throw Exceptions.createHandled() .withNLSKey("BaseEntityRefProperty.cannotDeleteEntityWithChildren") .set("count", count) .set("field", getLabel()) .set("type", getReferencedDescriptor().getLabel()) .set("source", getDescriptor().getLabel()) .handle(); } } }
protected void onDeleteReject(Object e) { BaseEntity<?> referenceInstance = (BaseEntity<?>) getDescriptor().getReferenceInstance(); long count = referenceInstance.getMapper() .select(referenceInstance.getClass()) .eq(nameAsMapping, ((BaseEntity<?>) e).getId()) .count(); if (count == 1) { throw Exceptions.createHandled() .withNLSKey("BaseEntityRefProperty.cannotDeleteEntityWithChild") .set("field", getLabel()) .set("type", getReferencedDescriptor().getLabel()) .set("source", getDescriptor().getLabel()) .handle(); } if (count > 1) { throw Exceptions.createHandled() .withNLSKey("BaseEntityRefProperty.cannotDeleteEntityWithChildren") .set("count", count) .set("field", getLabel()) .set("type", getReferencedDescriptor().getLabel()) .set("source", getDescriptor().getLabel()) .handle(); } } }
protected <E extends B> void performUpdate(E entity, boolean force) throws OptimisticLockException { if (entity == null) { return; } try { EntityDescriptor ed = entity.getDescriptor(); ed.beforeSave(entity); if (entity.isNew()) { createEntity(entity, ed); } else { updateEntity(entity, force, ed); } ed.afterSave(entity); } catch (OptimisticLockException e) { throw e; } catch (Exception e) { throw Exceptions.handle() .to(Mixing.LOG) .error(e) .withSystemErrorMessage("Unable to UPDATE %s (%s): %s (%s)", entity, entity.getClass().getSimpleName()) .handle(); } }
/** * Returns or creates the sub context of the given type. * <p> * The class of the sub context must provide a no-args constructor, as it will be instantiated if non existed. * * @param contextType the type of the sub-context to be returned. * @param <C> the type of the sub-context * @return an instance of the given type. If no instance was available, a new one is created */ @Nonnull @SuppressWarnings("unchecked") public <C extends SubContext> C get(Class<C> contextType) { try { SubContext result = subContext.get(contextType); if (result == null) { result = contextType.getDeclaredConstructor().newInstance(); subContext.put(contextType, result); } return (C) result; } catch (Exception e) { throw Exceptions.handle() .error(e) .withSystemErrorMessage("Cannot get instance of %s from current CallContext: %s (%s)", contextType.getName()) .handle(); } }
/** * Updates the entity in the database. * <p> * If the entity was modified in the database and those changes where not reflected * by the entity to be saved, this operation will fail. * * @param entity the entity to be written into the DB * @param <E> the type of the entity to update * @return the updated entity */ public <E extends Entity> E update(E entity) { try { return update(entity, true, false, true); } catch (OptimisticLockException e) { reportClash(entity); throw Exceptions.handle() .to(LOG) .error(e) .withSystemErrorMessage("Failed to update '%s' (%s): %s (%s)", entity.toDebugString(), entity.getId()) .handle(); } }
@SuppressWarnings("unchecked") @Override protected Object transformFromSource(Object value) { try { if (value == null) { return null; } Class<?> targetClass = getField().getAnnotation(NestedObject.class).value(); Object obj = targetClass.newInstance(); if (value instanceof Map) { Map<String, String> values = (Map<String, String>) value; for (Field innerField : targetClass.getDeclaredFields()) { fillField(obj, values, innerField); } } return obj; } catch (Exception e) { throw Exceptions.handle() .error(e) .to(IndexAccess.LOG) .withSystemErrorMessage("Cannot load POJO in %s: %s (%s)", toString()) .handle(); } }
protected HandledException checkUniqueness(HandledException previousError, EntityDescriptor descriptor, Property p, Object value) { Query<?> qry = index.select(getClass()).eq(p.getName(), value); if (!isNew()) { qry.notEq(IndexAccess.ID_FIELD, id); } Unique unique = p.getField().getAnnotation(Unique.class); setupRoutingForUniquenessCheck(descriptor, qry, unique); if (qry.exists()) { UserContext.setFieldError(p.getName(), NLS.toUserString(value)); if (previousError == null) { try { return Exceptions.createHandled() .withNLSKey("Entity.fieldMustBeUnique") .set("field", p.getFieldTitle()) .set("value", NLS.toUserString(p.getField().get(this))) .handle(); } catch (Exception e) { Exceptions.handle(e); } } } return previousError; }
/** * Extracts and converts the value from the given request. * * @param name name of the parameter to read * @param ctx the request to read the data from * @return the converted value which can be assigned to the field */ protected Object transformFromRequest(String name, WebContext ctx) { Value value = ctx.get(name); if (value.isEmptyString() && !field.getType().isPrimitive()) { return null; } Object result = value.coerce(field.getType(), null); if (result == null) { UserContext.setFieldError(name, value.get()); throw Exceptions.createHandled() .withNLSKey("Property.invalidInput") .set("field", NLS.get(field.getDeclaringClass().getSimpleName() + "." + name)) .set("value", value.asString()) .handle(); } return result; }
/** * Performs a database lookup to select the entity of the given type with the given id. * * @param type the type of entity to select * @param id the id (which can be either a long, Long or String) to select * @param info info provided as context (e.g. routing infos for Elasticsearch) * @param <E> the generic type of the entity to select * @return the entity wrapped as <tt>Optional</tt> or an empty optional if no entity with the given id exists */ public <E extends B> Optional<E> find(Class<E> type, Object id, ContextInfo... info) { try { if (Strings.isEmpty(id)) { return Optional.empty(); } EntityDescriptor ed = mixing.getDescriptor(type); return findEntity(id, ed, makeContext(info)); } catch (HandledException e) { throw e; } catch (Exception e) { throw Exceptions.handle() .to(Mixing.LOG) .error(e) .withSystemErrorMessage("Unable to FIND %s (%s): %s (%s)", type.getSimpleName(), id) .handle(); } }
/** * Helper method which can be used to parse a {@link SearchHit} into a POJO. This can be useful when using * aggregations to transform raw {@link SearchHit}s. * * @param searchHit a raw hit returned by ElasticSearch * @return the raw hit transformed into an object of the desired class */ public E transformHit(SearchHit searchHit) { try { EntityDescriptor descriptor = indexAccess.getDescriptor(clazz); E entity = clazz.newInstance(); entity.initSourceTracing(); entity.setId(searchHit.getId()); entity.setVersion(searchHit.getVersion()); entity.setMatchedNamedQueries(searchHit.getMatchedQueries()); descriptor.readSource(entity, searchHit.getSourceAsMap()); return entity; } catch (Exception e) { throw Exceptions.handle() .error(e) .to(IndexAccess.LOG) .withSystemErrorMessage("Cannot transform SearchHit to POJO: %s", toString()) .handle(); } }
/** * Ensures that the index for the given entity type and year exists and contains the appropriate mappings. * * @param ed the descriptor of the entity type * @param year the year to create the index for */ public void ensureYearlyIndexExists(EntityDescriptor ed, int year) { String name = elastic.determineYearIndex(ed, year); if (yearlyIndexExists(name)) { return; } try { createMapping(ed, name); checkedIndices.put(name, true); } catch (Exception e) { Exceptions.handle() .to(Elastic.LOG) .error(e) .withSystemErrorMessage("Failed to initialize dynamic index %s for %s: %s (%s)", name, ed.getType().getName()) .handle(); } } }
/** * Determines if the given index exists. * * @param index the name of the index * @return <tt>true</tt> if the index exists, <tt>false</tt> otherwise */ public boolean indexExists(String index) { try { return restClient.performRequest("HEAD", index).getStatusLine().getStatusCode() == 200; } catch (ResponseException e) { throw Exceptions.handle() .to(Elastic.LOG) .error(e) .withSystemErrorMessage("An error occurred when checking for index '%s': %s (%s)", index) .handle(); } catch (IOException e) { throw Exceptions.handle() .to(Elastic.LOG) .error(e) .withSystemErrorMessage("An IO error occurred when checking for index '%s': %s (%s)", index) .handle(); } } }
private void transformValue(Object obj, Map<String, String> valueMap, Field innerField) { try { innerField.setAccessible(true); Object val = innerField.get(obj); if (val != null) { if (val instanceof Amount) { valueMap.put(innerField.getName(), ((Amount) val).getAmount().toPlainString()); return; } valueMap.put(innerField.getName(), NLS.toMachineString(val)); } } catch (Exception e) { Exceptions.handle() .error(e) .to(IndexAccess.LOG) .withSystemErrorMessage("Cannot save POJO field %s of %s: %s (%s)", innerField.getName(), toString()) .handle(); } }
private void transformField(Object o, Map<String, Object> valueMap, Field innerField) { if (innerField.isAnnotationPresent(Transient.class) || Modifier.isStatic(innerField.getModifiers())) { return; } try { innerField.setAccessible(true); Object val = innerField.get(o); if (val != null) { if (val instanceof Map || val instanceof List) { valueMap.put(innerField.getName(), val); } else { valueMap.put(innerField.getName(), NLS.toMachineString(val)); } } } catch (Exception e) { Exceptions.handle() .error(e) .to(IndexAccess.LOG) .withSystemErrorMessage("Cannot save POJO field %s of %s: %s (%s)", innerField.getName(), toString()) .handle(); } }
protected <E extends B> void performDelete(E entity, boolean force) throws OptimisticLockException { if (entity == null || entity.isNew()) { return; } try { EntityDescriptor ed = entity.getDescriptor(); ed.beforeDelete(entity); deleteEntity(entity, force, ed); ed.afterDelete(entity); } catch (OptimisticLockException e) { throw e; } catch (Exception e) { throw Exceptions.handle() .to(Mixing.LOG) .error(e) .withSystemErrorMessage("Unable to DELETE %s (%s): %s (%s)", entity, entity.getClass().getSimpleName()) .handle(); } }
/** * Creates a new entity for the given reference instance. * * @param type the type from which the descriptor is filled */ protected EntityDescriptor(Class<?> type) { this.type = type; this.relationName = getAnnotation(RelationName.class).map(RelationName::value).orElse(type.getSimpleName().toLowerCase()); this.realm = getAnnotation(Realm.class).map(Realm::value).orElse(Mixing.DEFAULT_REALM); this.versioned = getAnnotation(Versioned.class).isPresent(); try { this.referenceInstance = type.getDeclaredConstructor().newInstance(); } catch (Exception e) { Exceptions.handle() .to(Mixing.LOG) .error(e) .withSystemErrorMessage("Cannot create reference instance of mapped type: %s - %s (%s)", type.getName()) .handle(); } loadLegacyInfo(type); }