/** * Removes the given type from the cache by firing the remove event and cleaning all existing * references. * * @param existingType * Existing type. * @param events * {@link Events} */ private void removeDueToTypeChange(Type existingType, Events events) { existingType.removeReferences(); fireAndSave(new NodeEvent(existingType, NodeEventType.REMOVED, null), events); log.warn("Type " + existingType + " removed from the class-cache as it changed the base type."); }
/** * {@inheritDoc} */ @Override public void informNodeChange(NodeEvent event) { if (NodeEventDetails.INITIALIZED.equals(event.getEventDetails())) { // if it's initialized type index it cause he have hash ImmutableType type = event.getType(); for (String hash : type.getHashes()) { storage.put(hash, type); } } else if (NodeEventType.CHANGED.equals(event.getEventType()) && NodeEventDetails.HASH_ADDED.equals(event.getEventDetails())) { // otherwise only index it if there is new hash available ImmutableType type = event.getType(); for (String hash : type.getHashes()) { if (!storage.containsKey(hash)) { storage.put(hash, type); } } } else if (NodeEventType.REMOVED.equals(event.getEventType())) { // if removed kill all links ImmutableType type = event.getType(); for (String hash : type.getHashes()) { storage.remove(hash); } } }
/** * {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public void informNodeChange(NodeEvent event) { if (NodeEventType.NEW.equals(event.getEventType())) { index((E) event.getType()); } else if (NodeEventType.REMOVED.equals(event.getEventType())) { remove(event.getType()); } }
/** * Merges given annotation when it exist in the structure as interface. * * @param given * {@link AnnotationType} * @param existing * {@link InterfaceType} * @param events * Events to process. */ private void mergeAnnotationAsInterface(AnnotationType given, InterfaceType existing, Events events) { for (ClassType classType : existing.getRealizingClasses()) { // this should update the references in the class type correctly classType.addInterface(given); } // must be specified as new, no other way fireAndSave(new NodeEvent(given, NodeEventType.NEW, NodeEventDetails.INITIALIZED), events); }
/** * merges/adds the given entity to the type in the structure. * * @param inputType * the type in the structure or null if not existing * @param givenType * the given entity * @param events * write notifications here. */ private void handleBaseEntity(Type inputType, Type givenType, Events events) { if (null == inputType) { // ADD the new element to the structure fireAndSave(new NodeEvent(givenType, NodeEventType.NEW, NodeEventDetails.INITIALIZED), events); // RESOLVE the references of the type resolveReferences(givenType, events); } else { if ((givenType instanceof AnnotationType) && (inputType instanceof InterfaceType)) { // special case, when annotation is used as interface must be handled in different // way mergeAnnotationAsInterface((AnnotationType) givenType, (InterfaceType) inputType, events); } else { // MERGE the existing element with the information from the given entity merge(inputType, givenType, events); } } }
@Test(dataProvider = "types", expectedExceptions = { ClassCacheModificationException.class }) public void addNewUnInitializedTypeThatWasNotKnown(Class<? extends Type> type) throws Exception { String fqn = "class"; when(lookup.findByFQN(fqn)).thenReturn(null); service.lookup = lookup; Type theClass = construct(type, fqn); Events events = service.merge(theClass); Events expected = new Events(); expected.addEvent(new NodeEvent(theClass, NodeEventType.NEW, NodeEventDetails.NOT_INITIALIZED)); assertEvents(events, expected); }
@Test(dataProvider = "types") public void addNewInitializedTypeThatWasNotKnown(Class<? extends Type> type) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; when(lookup.findByFQN(fqn)).thenReturn(null); service.lookup = lookup; Type theClass = construct(type, fqn, hash, modifiers); Events events = service.merge(theClass); Events expected = new Events(); expected.addEvent(new NodeEvent(theClass, NodeEventType.NEW, NodeEventDetails.INITIALIZED)); assertEvents(events, expected); }
@Test(dataProvider = "typesWithMethods") public void addNewMethodExceptionNotThere(Class<? extends Type> clazz) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; TypeWithMethods given = (TypeWithMethods) construct(clazz, fqn, hash, modifiers); String exceptionName = "ex"; ClassType exception = new ClassType(exceptionName); String mName = "a"; String mReturnType = "mReturnType"; MethodType m = build(mName, 0, mReturnType, null, new HashSet<>(Arrays.asList(exception)), null); given.addMethod(m); when(lookup.findByFQN(fqn)).thenReturn(null); when(lookup.findByFQN(exceptionName)).thenReturn(null); service.lookup = lookup; Events events = service.merge(given); // methods with different parameters are different methods and should not be merged. assertThat(given.getMethods(), hasItem(m)); assertThat(given.getMethods().size(), is(1)); Events expected = new Events(); expected.addEvent(new NodeEvent(given, NodeEventType.NEW, NodeEventDetails.INITIALIZED)); expected.addEvent(new NodeEvent(exception, NodeEventType.NEW, NodeEventDetails.NOT_INITIALIZED)); assertEvents(events, expected); }
@Test(dataProvider = "typesWithMethods") public void addNewMethodAnnotationNotThere(Class<? extends Type> clazz) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; TypeWithMethods c = (TypeWithMethods) construct(clazz, fqn, hash, modifiers); String mName = "mName"; String mReturnType = "mReturnType"; int mMod = 7; String aName = "aName"; AnnotationType a = new AnnotationType(aName); c.addMethod(build(mName, mMod, mReturnType, null, null, new HashSet<>(Arrays.asList(new AnnotationType[] { a })))); when(lookup.findByFQN(fqn)).thenReturn(null); when(lookup.findByFQN(aName)).thenReturn(null); service.lookup = lookup; Events events = service.merge(c); Events expected = new Events(); expected.addEvent(new NodeEvent(c, NodeEventType.NEW, NodeEventDetails.INITIALIZED)); expected.addEvent(new NodeEvent(a, NodeEventType.NEW, NodeEventDetails.NOT_INITIALIZED)); assertThat(c.getMethods().size(), is(1)); assertThat(c.getMethods(), hasItem(build(mName, mMod, mReturnType, null, null, new HashSet<>(Arrays.asList(new AnnotationType[] { a }))))); assertEvents(events, expected); }
@Test(dataProvider = "typesWithMethods") public void mergeWithNotInitializedNewMethodExceptionNotThere(Class<? extends Type> clazz) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; TypeWithMethods given = (TypeWithMethods) construct(clazz, fqn, hash, modifiers); TypeWithMethods stored = (TypeWithMethods) construct(clazz, fqn); String exceptionName = "ex"; ClassType exception = new ClassType(exceptionName); String mName = "a"; String mReturnType = "mReturnType"; MethodType m = build(mName, 0, mReturnType, null, new HashSet<>(Arrays.asList(exception)), null); given.addMethod(m); when(lookup.findByFQN(fqn)).thenReturn(stored); when(lookup.findByFQN(exceptionName)).thenReturn(null); service.lookup = lookup; Events events = service.merge(given); // methods with different parameters are different methods and should not be merged. assertThat(stored.getMethods(), hasItem(m)); assertThat(stored.getMethods().size(), is(1)); Events expected = new Events(); expected.addEvent(new NodeEvent(stored, NodeEventType.CHANGED, NodeEventDetails.INITIALIZED)); expected.addEvent(new NodeEvent(exception, NodeEventType.NEW, NodeEventDetails.NOT_INITIALIZED)); expected.addEvent(new NodeEvent(stored, NodeEventType.CHANGED, NodeEventDetails.METHOD_CHANGED_OR_ADDED)); assertEvents(events, expected); }
@Test(dataProvider = "typesWithMethods") public void mergeWithNotInitializedNewMethodAnnotationNotThere(Class<? extends Type> clazz) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; TypeWithMethods c = (TypeWithMethods) construct(clazz, fqn, hash, modifiers); String mName = "mName"; String mReturnType = "mReturnType"; int mMod = 7; String aName = "aName"; AnnotationType a = new AnnotationType(aName); c.addMethod(build(mName, mMod, mReturnType, null, null, new HashSet<>(Arrays.asList(new AnnotationType[] { a })))); TypeWithMethods stored = (TypeWithMethods) construct(clazz, fqn); when(lookup.findByFQN(fqn)).thenReturn(stored); when(lookup.findByFQN(aName)).thenReturn(null); service.lookup = lookup; Events events = service.merge(c); Events expected = new Events(); expected.addEvent(new NodeEvent(stored, NodeEventType.CHANGED, NodeEventDetails.INITIALIZED)); expected.addEvent(new NodeEvent(a, NodeEventType.NEW, NodeEventDetails.NOT_INITIALIZED)); expected.addEvent(new NodeEvent(stored, NodeEventType.CHANGED, NodeEventDetails.METHOD_CHANGED_OR_ADDED)); assertThat(stored.getMethods().size(), is(1)); assertThat(stored.getMethods(), hasItem(build(mName, mMod, mReturnType, null, null, new HashSet<>(Arrays.asList(new AnnotationType[] { a }))))); assertEvents(events, expected); }
@Test(dataProvider = "typesWithMethods") public void addNewMethodAnnotationThere(Class<? extends Type> clazz) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; TypeWithMethods c = (TypeWithMethods) construct(clazz, fqn, hash, modifiers); String mName = "mName"; String mReturnType = "mReturnType"; int mMod = 7; String aName = "aName"; AnnotationType a = new AnnotationType(aName); c.addMethod(build(mName, mMod, mReturnType, null, null, new HashSet<>(Arrays.asList(new AnnotationType[] { a })))); when(lookup.findByFQN(fqn)).thenReturn(null); when(lookup.findByFQN(aName)).thenReturn(a); service.lookup = lookup; Events events = service.merge(c); Events expected = new Events(); expected.addEvent(new NodeEvent(c, NodeEventType.NEW, NodeEventDetails.INITIALIZED)); assertThat(c.getMethods().size(), is(1)); assertThat(c.getMethods(), hasItem(build(mName, mMod, mReturnType, null, null, new HashSet<>(Arrays.asList(new AnnotationType[] { a }))))); assertEvents(events, expected); }
@Test(dataProvider = "typesWithMethods") public void mergeWithNotInitializedNewMethodAnnotationThere(Class<? extends Type> clazz) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; TypeWithMethods c = (TypeWithMethods) construct(clazz, fqn, hash, modifiers); String mName = "mName"; String mReturnType = "mReturnType"; int mMod = 7; String aName = "aName"; AnnotationType a = new AnnotationType(aName); c.addMethod(build(mName, mMod, mReturnType, null, null, new HashSet<>(Arrays.asList(new AnnotationType[] { a })))); TypeWithMethods stored = (TypeWithMethods) construct(clazz, fqn); when(lookup.findByFQN(fqn)).thenReturn(stored); when(lookup.findByFQN(aName)).thenReturn(a); service.lookup = lookup; Events events = service.merge(c); Events expected = new Events(); expected.addEvent(new NodeEvent(stored, NodeEventType.CHANGED, NodeEventDetails.INITIALIZED)); expected.addEvent(new NodeEvent(stored, NodeEventType.CHANGED, NodeEventDetails.METHOD_CHANGED_OR_ADDED)); assertThat(stored.getMethods().size(), is(1)); assertThat(stored.getMethods(), hasItem(build(mName, mMod, mReturnType, null, null, new HashSet<>(Arrays.asList(new AnnotationType[] { a }))))); assertEvents(events, expected); }
@Test(dataProvider = "typesWithMethods") public void addNewMethodExceptionThere(Class<? extends Type> clazz) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; TypeWithMethods given = (TypeWithMethods) construct(clazz, fqn, hash, modifiers); String exceptionName = "ex"; ClassType exception = new ClassType(exceptionName); String mName = "a"; String mReturnType = "mReturnType"; MethodType m = build(mName, 0, mReturnType, null, new HashSet<>(Arrays.asList(exception)), null); given.addMethod(m); when(lookup.findByFQN(fqn)).thenReturn(null); when(lookup.findByFQN(exceptionName)).thenReturn(exception); service.lookup = lookup; Events events = service.merge(given); // methods with different parameters are different methods and should not be merged. assertThat(given.getMethods(), hasItem(m)); assertThat(given.getMethods().size(), is(1)); Events expected = new Events(); expected.addEvent(new NodeEvent(given, NodeEventType.NEW, NodeEventDetails.INITIALIZED)); assertEvents(events, expected); }
@Test(dataProvider = "types") public void addNewAnnotationReferredTypeNotThere(Class<? extends Type> clazz) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; TypeWithAnnotations c = construct(clazz, fqn, hash, modifiers); String annotationFQN = "fqnAnnotation"; AnnotationType annotation = new AnnotationType(annotationFQN); c.addAnnotation(annotation); // we assume that nothing is there yet when(lookup.findByFQN(fqn)).thenReturn((Type) null); when(lookup.findByFQN(annotationFQN)).thenReturn(null); service.lookup = lookup; Events events = service.merge((Type) c); // assert bidirectional assertThat(c.getAnnotations().size(), is(1)); assertThat(c.getAnnotations(), hasItem(annotation)); assertThat(annotation.getAnnotatedTypes(), hasItem(c)); Events expected = new Events(); expected.addEvent(new NodeEvent((Type) c, NodeEventType.NEW, NodeEventDetails.INITIALIZED)); expected.addEvent(new NodeEvent(annotation, NodeEventType.NEW, NodeEventDetails.NOT_INITIALIZED)); expected.addEvent(new ReferenceEvent((Type) c, annotation, ReferenceType.ANNOTATION)); assertEvents(events, expected); }
@Test(dataProvider = "types") public void addNewInitializedTypeThatIsKnownUninitialized(Class<? extends Type> type) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; Type notInitialized = construct(type, fqn); when(lookup.findByFQN(fqn)).thenReturn(notInitialized); service.lookup = lookup; Type initialized = construct(type, fqn, hash, modifiers); Events events = service.merge(initialized); Events expected = new Events(); expected.addEvent(new NodeEvent(notInitialized, NodeEventType.CHANGED, NodeEventDetails.INITIALIZED)); assertEvents(events, expected); }
@Test(dataProvider = "typesWithMethods") public void mergeWithNotInitializedNewMethodExceptionThere(Class<? extends Type> clazz) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; TypeWithMethods given = (TypeWithMethods) construct(clazz, fqn, hash, modifiers); TypeWithMethods stored = (TypeWithMethods) construct(clazz, fqn); String exceptionName = "ex"; ClassType exception = new ClassType(exceptionName); String mName = "a"; String mReturnType = "mReturnType"; MethodType m = build(mName, 0, mReturnType, null, new HashSet<>(Arrays.asList(exception)), null); given.addMethod(m); when(lookup.findByFQN(fqn)).thenReturn(stored); when(lookup.findByFQN(exceptionName)).thenReturn(exception); service.lookup = lookup; Events events = service.merge(given); // methods with different parameters are different methods and should not be merged. assertThat(stored.getMethods(), hasItem(m)); assertThat(stored.getMethods().size(), is(1)); Events expected = new Events(); expected.addEvent(new NodeEvent(stored, NodeEventType.CHANGED, NodeEventDetails.INITIALIZED)); expected.addEvent(new NodeEvent(stored, NodeEventType.CHANGED, NodeEventDetails.METHOD_CHANGED_OR_ADDED)); assertEvents(events, expected); }
@Test public void addNewSuperclassReferenceReferredTypeNotThere() throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; ClassType c = new ClassType(fqn, hash, modifiers); String fqnSuper = "fqnSuper"; ClassType s = new ClassType(fqnSuper); c.addSuperClass(s); when(lookup.findByFQN(fqn)).thenReturn(null); when(lookup.findByFQN(fqnSuper)).thenReturn(null); service.lookup = lookup; Events events = service.merge(c); Events expected = new Events(); expected.addEvent(new NodeEvent(c, NodeEventType.NEW, NodeEventDetails.INITIALIZED)); expected.addEvent(new NodeEvent(s, NodeEventType.NEW, NodeEventDetails.NOT_INITIALIZED)); expected.addEvent(new ReferenceEvent(c, s, ReferenceType.SUPERCLASS)); // assert bidirectional assertThat(c.getSuperClasses().size(), is(1)); assertThat(c.getSuperClasses(), hasItem(s)); assertThat(s.getSubClasses(), hasItem(c)); assertEvents(events, expected); }
@Test(dataProvider = "typesWithMethods") public void mergeWithNotInitializedNewMethodReturnType(Class<? extends Type> clazz) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; TypeWithMethods c = (TypeWithMethods) construct(clazz, fqn, hash, modifiers); String mName = "mName"; int mMod = 7; String returnType = "void"; List<String> params = Arrays.asList(new String[] { "java.util.List", "java.lang.String" }); c.addMethod(build(mName, mMod, returnType, params, null, null)); TypeWithMethods stored = (TypeWithMethods) construct(clazz, fqn); when(lookup.findByFQN(fqn)).thenReturn(stored); service.lookup = lookup; Events events = service.merge(c); Events expected = new Events(); expected.addEvent(new NodeEvent(c, NodeEventType.CHANGED, NodeEventDetails.INITIALIZED)); expected.addEvent(new NodeEvent(stored, NodeEventType.CHANGED, NodeEventDetails.METHOD_CHANGED_OR_ADDED)); String returnTypeExpected = "void"; assertThat(stored.getMethods().size(), is(1)); assertThat(stored.getMethods(), hasItem(build(mName, mMod, returnTypeExpected, params, null, null))); assertEvents(events, expected); }