예제 #1
0
    /**
     * Returns the singleton application object matching the given {@code applicationClass} within
     * the given {@code database}.
     */
    @SuppressWarnings("unchecked")
    public static <T extends Application> T getInstanceUsing(
        Class<T> applicationClass, Database database) {

      ObjectType type = database.getEnvironment().getTypeByClass(applicationClass);
      Query<T> query =
          Query.from(applicationClass).where("_type = ?", type.getId()).using(database);
      T app = query.first();

      if (app == null) {
        DistributedLock lock =
            DistributedLock.Static.getInstance(database, applicationClass.getName());
        lock.lock();

        try {
          app = query.clone().noCache().first();
          if (app == null) {
            app = (T) type.createObject(null);
            app.setName(type.getDisplayName());
            app.saveImmediately();
            return app;
          }

        } finally {
          lock.unlock();
        }
      }

      String oldName = app.getName();
      String newName = type.getDisplayName();
      if (!ObjectUtils.equals(oldName, newName)) {
        app.setName(newName);
        app.save();
      }

      return app;
    }
예제 #2
0
  /** Immediately refreshes all types using the backing database. */
  public synchronized void refreshTypes() {
    bootstrapOnce.ensure();

    Database database = getDatabase();
    try {

      TypesCache temporaryTypes = temporaryTypesLocal.get();
      if (temporaryTypes == null) {
        temporaryTypes = new TypesCache();
        temporaryTypesLocal.set(temporaryTypes);
      }

      List<ObjectType> types = Query.from(ObjectType.class).using(database).selectAll();
      int typesSize = types.size();
      LOGGER.info("Loading [{}] types from [{}]", typesSize, database.getName());

      // Load all types from the database first.
      for (ObjectType type : types) {
        type.getFields().size(); // Pre-fetch.
        temporaryTypes.add(type);
      }

      if (initializeClasses) {

        // Make sure that the root type exists.
        ObjectType rootType = getRootType();
        State rootTypeState;

        if (rootType != null) {
          rootTypeState = rootType.getState();

        } else {
          rootType = new ObjectType();
          rootTypeState = rootType.getState();
          rootTypeState.setDatabase(database);
        }

        Map<String, Object> rootTypeOriginals = rootTypeState.getSimpleValues();
        UUID rootTypeId = rootTypeState.getId();
        rootTypeState.setTypeId(rootTypeId);
        rootTypeState.clear();
        rootType.setObjectClassName(ObjectType.class.getName());
        rootType.initialize();
        temporaryTypes.add(rootType);

        try {
          database.beginWrites();

          // Make the new root type available to other types.
          temporaryTypes.add(rootType);
          if (rootTypeState.isNew()) {
            State globals = getGlobals();
            globals.put(ROOT_TYPE_FIELD, rootType);
            globals.save();

          } else if (!rootTypeState.getSimpleValues().equals(rootTypeOriginals)) {
            temporaryTypes.changed.add(rootTypeId);
          }

          Set<Class<? extends Recordable>> objectClasses =
              ClassFinder.findClasses(Recordable.class);

          for (Iterator<Class<? extends Recordable>> i = objectClasses.iterator(); i.hasNext(); ) {
            Class<? extends Recordable> objectClass = i.next();

            try {
              if (objectClass.isAnonymousClass()
                  || Substitution.class.isAssignableFrom(objectClass)) {
                i.remove();
              }

            } catch (IncompatibleClassChangeError error) {
              i.remove();
            }
          }

          Set<Class<?>> globalModifications = new HashSet<Class<?>>();
          Map<ObjectType, List<Class<?>>> typeModifications =
              new HashMap<ObjectType, List<Class<?>>>();

          // Make sure all types are accessible to the rest of the
          // system as soon as possible, so that references can be
          // resolved properly later.
          for (Class<?> objectClass : objectClasses) {
            ObjectType type = getTypeByClass(objectClass);

            if (type == null) {
              type = new ObjectType();
              type.getState().setDatabase(database);

            } else {
              type.getState().clear();
            }

            type.setObjectClassName(objectClass.getName());
            typeModifications.put(type, new ArrayList<Class<?>>());
            temporaryTypes.add(type);
          }

          // Separate out all modifications from regular types.
          for (Class<?> objectClass : objectClasses) {
            if (!Modification.class.isAssignableFrom(objectClass)) {
              continue;
            }

            @SuppressWarnings("unchecked")
            Set<Class<?>> modifiedClasses =
                Modification.Static.getModifiedClasses(
                    (Class<? extends Modification<?>>) objectClass);
            if (modifiedClasses.contains(Object.class)) {
              globalModifications.add(objectClass);
              continue;
            }

            for (Class<?> modifiedClass : modifiedClasses) {
              List<Class<?>> assignableClasses = new ArrayList<Class<?>>();

              for (Class<?> c : objectClasses) {
                if (modifiedClass.isAssignableFrom(c)) {
                  assignableClasses.add(c);
                }
              }

              for (Class<?> assignableClass : assignableClasses) {
                ObjectType type = getTypeByClass(assignableClass);

                if (type != null) {
                  List<Class<?>> modifications = typeModifications.get(type);
                  if (modifications == null) {
                    modifications = new ArrayList<Class<?>>();
                    typeModifications.put(type, modifications);
                  }
                  modifications.add(objectClass);
                }
              }
            }
          }

          // Apply global modifications.
          for (Class<?> modification : globalModifications) {
            ObjectType.modifyAll(database, modification);
          }

          // Initialize all types.
          List<Class<?>> rootTypeModifications = typeModifications.remove(rootType);
          initializeAndModify(temporaryTypes, rootType, rootTypeModifications);

          if (rootTypeModifications != null) {
            for (Class<?> modification : rootTypeModifications) {
              ObjectType t = getTypeByClass(modification);
              initializeAndModify(temporaryTypes, t, typeModifications.remove(t));
            }
          }

          ObjectType fieldType = getTypeByClass(ObjectField.class);
          List<Class<?>> fieldModifications = typeModifications.remove(fieldType);
          initializeAndModify(temporaryTypes, fieldType, fieldModifications);

          if (fieldModifications != null) {
            for (Class<?> modification : fieldModifications) {
              ObjectType t = getTypeByClass(modification);
              initializeAndModify(temporaryTypes, t, typeModifications.remove(t));
            }
          }

          for (Map.Entry<ObjectType, List<Class<?>>> entry : typeModifications.entrySet()) {
            initializeAndModify(temporaryTypes, entry.getKey(), entry.getValue());
          }

          database.commitWrites();

        } finally {
          database.endWrites();
        }
      }

      // Merge temporary types into new permanent types.
      TypesCache newPermanentTypes = new TypesCache();

      for (ObjectType type : permanentTypes.byId.values()) {
        newPermanentTypes.add(type);
      }

      for (ObjectType type : temporaryTypes.byId.values()) {
        newPermanentTypes.add(type);
      }

      newPermanentTypes.changed.addAll(temporaryTypes.changed);
      newPermanentTypes.changed.addAll(permanentTypes.changed);

      // If any types changed, clear all types' extras.
      if (!temporaryTypes.changed.isEmpty()) {
        for (ObjectType type : newPermanentTypes.byId.values()) {
          type.getState().getExtras().clear();
        }
      }

      permanentTypes = newPermanentTypes;
      lastTypesUpdate = new Date();

    } finally {
      temporaryTypesLocal.remove();
    }

    ObjectType singletonType = getTypeByClass(Singleton.class);

    if (singletonType != null) {
      for (ObjectType type : singletonType.findConcreteTypes()) {
        if (!Query.fromType(type).where("_type = ?", type).master().noCache().hasMoreThan(0)) {
          try {
            State.getInstance(type.createObject(null)).saveImmediately();
          } catch (Exception error) {
            LOGGER.warn(String.format("Can't save [%s] singleton!", type.getLabel()), error);
          }
        }
      }
    }

    for (ObjectType type : getTypes()) {
      Class<?> objectClass = type.getObjectClass();
      if (objectClass != null) {
        TypePostProcessorClasses tppcAnnotation =
            objectClass.getAnnotation(TypePostProcessorClasses.class);
        if (tppcAnnotation != null) {
          for (Class<? extends ObjectType.PostProcessor> processorClass : tppcAnnotation.value()) {
            ObjectType.PostProcessor processor =
                (ObjectType.PostProcessor) TYPE_POST_PROCESSORS.getUnchecked(processorClass);
            processor.process(type);
          }
        }
      }
    }
  }