Java tutorial
/* * Copyright 2010-2011 Andreas Veithen * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.googlecode.arit.websphere.jaxb; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBIntrospector; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import com.github.veithen.rbeans.RBeanFactory; import com.github.veithen.rbeans.RBeanFactoryException; import com.googlecode.arit.Formatter; import com.googlecode.arit.Messages; import com.googlecode.arit.resource.ClassLoaderReference; import com.googlecode.arit.resource.CleanerPlugin; import com.googlecode.arit.resource.Resource; import com.googlecode.arit.resource.ResourceScanner; import com.googlecode.arit.resource.ResourceScanningConfig; import com.googlecode.arit.resource.ResourceType; import com.googlecode.arit.resource.SimpleClassLoaderReference; public class JAXBUtilsPoolScanner implements ResourceScanner, CleanerPlugin { private static final Log LOG = LogFactory.getLog(JAXBUtilsPoolScanner.class); @Autowired(required = false) private Messages messages; @Autowired private ResourceScanningConfig config; @Autowired @Qualifier("ws-cached-jaxb-object") private ResourceType resourceType; private final RBeanFactory rbf; private final JAXBUtilsRBean jaxbUtils; public JAXBUtilsPoolScanner() { RBeanFactory rbf; try { rbf = new RBeanFactory(JAXBUtilsRBean.class, JAXBContextImplRBean.class); } catch (RBeanFactoryException ex) { rbf = null; } this.rbf = rbf; jaxbUtils = rbf == null ? null : rbf.createRBean(JAXBUtilsRBean.class); } public boolean isAvailable() { return rbf != null; } public void scanForResources(ResourceListener resourceListener) { if (!config.includeGarbageCollectableResources()) { return; } for (Entry<Class<?>, PoolRBean> poolEntry : getPools().entrySet()) { Class<?> cachedObjectType = poolEntry.getKey(); Map<JAXBContext, List<?>> jaxbContextMap = poolEntry.getValue().getSoftMap().get(); if (jaxbContextMap != null) { for (Entry<JAXBContext, List<?>> contextEntry : jaxbContextMap.entrySet()) { Set<ClassLoader> classLoaders = getClassLoaders(contextEntry.getKey()); resourceListener .onResourceFound(new JAXBContextResource(contextEntry, classLoaders, cachedObjectType)); } } } } public String getDescription() { return "Cached JAXB objects"; } private Map<Class<?>, PoolRBean> getPools() { Map<Class<?>, PoolRBean> pools = new HashMap<Class<?>, PoolRBean>(); pools.put(JAXBIntrospector.class, jaxbUtils.getIPool()); pools.put(Marshaller.class, jaxbUtils.getMPool()); pools.put(Unmarshaller.class, jaxbUtils.getUPool()); return pools; } public Set<ClassLoader> getClassLoaders(JAXBContext context) { Set<ClassLoader> classLoaders = new HashSet<ClassLoader>(); if (rbf.getRBeanInfo(JAXBContextImplRBean.class).getTargetClass().isInstance(context)) { JAXBModelRBean model = rbf.createRBean(JAXBContextImplRBean.class, context).getModel(); // The model may be null if the JAXBContextImpl failed to create the model if (model != null) { for (ValueTypeInformationRBean typeInformation : model.getTypeInformation()) { classLoaders.add(typeInformation.getJavaType().getClassLoader()); } } } else { String msg = "Encountered unexpected JAXBContext implementation " + context.getClass().getName(); LOG.warn(msg); if (messages != null) { messages.addMessage(msg); } } return classLoaders; } public void clean(ClassLoader classLoader) { for (Map.Entry<Class<?>, PoolRBean> poolsEntry : getPools().entrySet()) { Class<?> pooledObjectType = poolsEntry.getKey(); Map<JAXBContext, List<?>> map = poolsEntry.getValue().getSoftMap().get(); if (map != null) { // The map is a ConcurrentHashMap, so no synchronization is required for (Iterator<Map.Entry<JAXBContext, List<?>>> it = map.entrySet().iterator(); it.hasNext();) { Map.Entry<JAXBContext, List<?>> entry = it.next(); if (getClassLoaders(entry.getKey()).contains(classLoader)) { it.remove(); LOG.info("Removed pooled " + pooledObjectType.getSimpleName() + "(s)"); } } } } } public class JAXBContextResource implements Resource<Map.Entry<JAXBContext, List<?>>> { private final Map.Entry<JAXBContext, List<?>> entry; private final Set<ClassLoaderReference> classLoaderReferences; private final Class<?> cachedObjectType; public JAXBContextResource(Entry<JAXBContext, List<?>> entry, Set<ClassLoader> classLoaders, Class<?> cachedObjectType) { this.entry = entry; this.classLoaderReferences = new HashSet<ClassLoaderReference>(classLoaders.size()); for (ClassLoader classLoader : classLoaders) { classLoaderReferences.add(new SimpleClassLoaderReference(classLoader, "JAXBContext")); } this.cachedObjectType = cachedObjectType; } public ResourceType getResourceType() { return resourceType; } public Map.Entry<JAXBContext, List<?>> getResourceObject() { return entry; } public String getDescription(Formatter formatter) { return "Cached " + cachedObjectType.getSimpleName(); } public Set<ClassLoaderReference> getClassLoaderReferences() { return classLoaderReferences; } public boolean isGarbageCollectable() { return true; } } }