| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 org.apache.sling.event.dea.impl; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.ObjectInputStream; |
| import java.io.Serializable; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.sling.api.resource.PersistenceException; |
| import org.apache.sling.api.resource.Resource; |
| import org.apache.sling.api.resource.ResourceResolver; |
| import org.apache.sling.api.resource.ResourceUtil; |
| import org.apache.sling.api.resource.ValueMap; |
| |
| public abstract class ResourceHelper { |
| |
| public static final String PROPERTY_MARKER_READ_ERROR_LIST = ResourceHelper.class.getName() + "/ReadErrorList"; |
| |
| public static Map<String, Object> cloneValueMap(final ValueMap vm) throws InstantiationException { |
| List<Exception> hasReadError = null; |
| try { |
| final Map<String, Object> result = new HashMap<String, Object>(vm); |
| for(final Map.Entry<String, Object> entry : result.entrySet()) { |
| if ( entry.getValue() instanceof InputStream ) { |
| final Object value = vm.get(entry.getKey(), Serializable.class); |
| if ( value != null ) { |
| entry.setValue(value); |
| } else { |
| if ( hasReadError == null ) { |
| hasReadError = new ArrayList<Exception>(); |
| } |
| final int count = hasReadError.size(); |
| // let's find out which class might be missing |
| ObjectInputStream ois = null; |
| try { |
| ois = new ObjectInputStream((InputStream)entry.getValue()); |
| ois.readObject(); |
| } catch (final ClassNotFoundException cnfe) { |
| hasReadError.add(new Exception("Unable to deserialize property '" + entry.getKey() + "'", cnfe)); |
| } catch (final IOException ioe) { |
| hasReadError.add(new Exception("Unable to deserialize property '" + entry.getKey() + "'", ioe)); |
| } finally { |
| if ( ois != null ) { |
| try { |
| ois.close(); |
| } catch (IOException ignore) { |
| // ignore |
| } |
| } |
| } |
| if ( hasReadError.size() == count ) { |
| hasReadError.add(new Exception("Unable to deserialize property '" + entry.getKey() + "'")); |
| } |
| } |
| } |
| } |
| if ( hasReadError != null ) { |
| result.put(PROPERTY_MARKER_READ_ERROR_LIST, hasReadError); |
| } |
| return result; |
| } catch ( final IllegalArgumentException iae) { |
| // the JCR implementation might throw an IAE if something goes wrong |
| throw (InstantiationException)new InstantiationException(iae.getMessage()).initCause(iae); |
| } |
| } |
| |
| public static ValueMap getValueMap(final Resource resource) throws InstantiationException { |
| final ValueMap vm = ResourceUtil.getValueMap(resource); |
| // trigger full loading |
| try { |
| vm.size(); |
| } catch ( final IllegalArgumentException iae) { |
| // the JCR implementation might throw an IAE if something goes wrong |
| throw (InstantiationException)new InstantiationException(iae.getMessage()).initCause(iae); |
| } |
| return vm; |
| } |
| |
| /** |
| * A batch resource remover deletes resources in batches. Once the batch |
| * size (threshold) is reached, an intermediate commit is performed. Resource |
| * trees are deleted resource by resource starting with the deepest children first. |
| * Once all resources have been passed to the batch resource remover, a final |
| * commit needs to be called on the resource resolver. |
| */ |
| public static class BatchResourceRemover { |
| |
| private final int max; |
| |
| private int count; |
| |
| public BatchResourceRemover(final int batchSize) { |
| this.max = (batchSize < 1 ? 50 : batchSize); |
| } |
| |
| public void delete(final Resource rsrc) |
| throws PersistenceException { |
| final ResourceResolver resolver = rsrc.getResourceResolver(); |
| for(final Resource child : rsrc.getChildren()) { |
| delete(child); |
| } |
| resolver.delete(rsrc); |
| count++; |
| if ( count >= max ) { |
| resolver.commit(); |
| count = 0; |
| } |
| } |
| } |
| |
| /** |
| * Create a batch resource remover. |
| * A batch resource remove can be used to delete resources in batches. |
| * Once the passed in threshold of deleted resources is reached, an intermediate |
| * commit is called on the resource resolver. In addition the batch remover |
| * deletes a resource recursively. |
| * Once all resources to delete are passed to the remover, a final commit needs |
| * to be call on the resource resolver. |
| * @param threshold The threshold for the intermediate saves. |
| * @return A new batch resource remover. |
| */ |
| public static BatchResourceRemover getBatchResourceRemover(final int threshold) { |
| return new BatchResourceRemover(threshold); |
| } |
| } |