| /* |
| * 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.installer.it; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotNull; |
| |
| import java.io.InputStream; |
| import java.util.ArrayList; |
| import java.util.Dictionary; |
| import java.util.HashMap; |
| import java.util.Hashtable; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.concurrent.BrokenBarrierException; |
| import java.util.concurrent.CyclicBarrier; |
| import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.TimeoutException; |
| |
| import org.apache.sling.installer.api.InstallableResource; |
| import org.apache.sling.installer.api.ResourceChangeListener; |
| import org.apache.sling.installer.api.UpdateHandler; |
| import org.apache.sling.installer.api.UpdateResult; |
| import org.apache.sling.installer.api.event.InstallationEvent; |
| import org.apache.sling.installer.api.event.InstallationListener; |
| import org.apache.sling.installer.api.tasks.ChangeStateTask; |
| import org.apache.sling.installer.api.tasks.InstallTask; |
| import org.apache.sling.installer.api.tasks.InstallTaskFactory; |
| import org.apache.sling.installer.api.tasks.RegisteredResource; |
| import org.apache.sling.installer.api.tasks.ResourceState; |
| import org.apache.sling.installer.api.tasks.ResourceTransformer; |
| import org.apache.sling.installer.api.tasks.TaskResource; |
| import org.apache.sling.installer.api.tasks.TaskResourceGroup; |
| import org.apache.sling.installer.api.tasks.TransformationResult; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.ops4j.pax.exam.Option; |
| import org.ops4j.pax.exam.junit.PaxExam; |
| import org.osgi.framework.Constants; |
| import org.osgi.framework.ServiceRegistration; |
| |
| @RunWith(PaxExam.class) |
| |
| public class UpdateHandlerTest extends OsgiInstallerTestBase { |
| |
| private static final String TYPE = "special"; |
| |
| private final List<ServiceRegistration<?>> serviceRegistrations = new ArrayList<ServiceRegistration<?>>(); |
| |
| private final Map<String, Dictionary<String, Object>> installed = new HashMap<String, Dictionary<String,Object>>(); |
| |
| @org.ops4j.pax.exam.Configuration |
| public Option[] config() { |
| return defaultConfiguration(); |
| } |
| |
| @Before |
| public void setUp() { |
| setupInstaller(); |
| serviceRegistrations.clear(); |
| |
| final Dictionary<String, Object> props = new Hashtable<String, Object>(); |
| props.put(Constants.SERVICE_RANKING, 1000); |
| |
| serviceRegistrations.add(this.bundleContext.registerService(ResourceTransformer.class, |
| new ResourceTransformer() { |
| |
| public TransformationResult[] transform(final RegisteredResource resource) { |
| final int lastDot = resource.getURL().lastIndexOf('.'); |
| final int lastSlash = resource.getURL().lastIndexOf('/'); |
| if ( resource.getURL().substring(lastDot + 1).equals(TYPE) ) { |
| final String id = resource.getURL().substring(lastSlash + 1, lastDot); |
| final TransformationResult tr = new TransformationResult(); |
| tr.setId(id); |
| tr.setResourceType(TYPE); |
| |
| return new TransformationResult[] {tr}; |
| } |
| return null; |
| } |
| }, props)); |
| serviceRegistrations.add(this.bundleContext.registerService(InstallTaskFactory.class, |
| new InstallTaskFactory() { |
| |
| public InstallTask createTask(final TaskResourceGroup toActivate) { |
| final TaskResource tr = toActivate.getActiveResource(); |
| if ( tr != null && tr.getEntityId().startsWith(TYPE) ) { |
| if ( tr.getState() == ResourceState.INSTALL ) { |
| installed.put(tr.getEntityId(), tr.getDictionary()); |
| return new ChangeStateTask(toActivate, ResourceState.INSTALLED); |
| } else { |
| installed.remove(tr.getEntityId()); |
| return new ChangeStateTask(toActivate, ResourceState.UNINSTALLED); |
| } |
| } |
| return null; |
| } |
| }, props)); |
| } |
| |
| @Override |
| @After |
| public void tearDown() { |
| for(final ServiceRegistration<?> reg : this.serviceRegistrations) { |
| reg.unregister(); |
| } |
| this.serviceRegistrations.clear(); |
| super.tearDown(); |
| } |
| |
| private static final class UpdateHandlerImpl implements UpdateHandler { |
| |
| private final Barrier barrier = new Barrier(2); |
| |
| private volatile UpdateResult result; |
| |
| public UpdateResult handleUpdate(String resourceType, String id, |
| String url, InputStream is, Map<String, Object> attributes) { |
| // we only test dictionaries |
| return null; |
| } |
| |
| public UpdateResult handleUpdate(final String resourceType, |
| final String id, |
| final String url, |
| final Dictionary<String, Object> dict, |
| final Map<String, Object> attributes) { |
| if ( resourceType.equals(TYPE)) { |
| final UpdateResult ur = new UpdateResult(TYPE + ":/resource/b/" + id + "." + resourceType); |
| this.result = ur; |
| this.barrier.block(); |
| |
| return ur; |
| } |
| return null; |
| } |
| |
| public UpdateResult handleRemoval(String resourceType, String id, String url) { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| |
| public UpdateResult waitForUpdate() { |
| barrier.block(); |
| |
| final UpdateResult r = this.result; |
| this.result = null; |
| barrier.reset(); |
| return r; |
| } |
| }; |
| |
| private Barrier getInstallerListenerBarrier() { |
| final Barrier b = new Barrier(2); |
| final InstallationListener il = new InstallationListener() { |
| public void onEvent(final InstallationEvent event) { |
| if ( event.getType() == InstallationEvent.TYPE.PROCESSED ) { |
| b.block(); |
| } |
| } |
| }; |
| b.reg = bundleContext.registerService(InstallationListener.class.getName(), il, null); |
| return b; |
| } |
| |
| @Test |
| public void testSimpleUpdate() throws Exception { |
| final UpdateHandlerImpl up = new UpdateHandlerImpl(); |
| final Dictionary<String, Object> dict = new Hashtable<String, Object>(); |
| dict.put(UpdateHandler.PROPERTY_SCHEMES, TYPE); |
| |
| this.serviceRegistrations.add(this.bundleContext.registerService(UpdateHandler.class, up, dict)); |
| |
| final Dictionary<String, Object> data = new Hashtable<String, Object>(); |
| data.put("foo", "bar"); |
| |
| final InstallableResource ir = new InstallableResource("/resource/a." + TYPE, |
| null, data, null, InstallableResource.TYPE_PROPERTIES, null); |
| |
| final Barrier b = this.getInstallerListenerBarrier(); |
| this.installer.registerResources(TYPE, new InstallableResource[] {ir}); |
| b.block(); |
| b.reg.unregister(); |
| |
| assertNotNull("Resource should be installed: " + installed, installed.get(TYPE) + ":a"); |
| |
| final ResourceChangeListener rcl = (ResourceChangeListener)this.installer; |
| |
| final Dictionary<String, Object> newData = new Hashtable<String, Object>(); |
| data.put("bar", "foo"); |
| rcl.resourceAddedOrUpdated(TYPE, "a", null, newData, null); |
| |
| final UpdateResult ur = up.waitForUpdate(); |
| assertNotNull(ur); |
| assertEquals(TYPE + ":/resource/b/a." + TYPE, ur.getURL()); |
| } |
| |
| /** Simplified version of the cyclic barrier class for testing. */ |
| public static final class Barrier extends CyclicBarrier { |
| |
| public Barrier(final int parties) { |
| super(parties); |
| } |
| |
| public void block() { |
| try { |
| this.await(); |
| } catch (InterruptedException e) { |
| // ignore |
| } catch (BrokenBarrierException e) { |
| // ignore |
| } |
| } |
| |
| public boolean block(int seconds) { |
| try { |
| this.await(seconds, TimeUnit.SECONDS); |
| return true; |
| } catch (InterruptedException e) { |
| // ignore |
| } catch (BrokenBarrierException e) { |
| // ignore |
| } catch (TimeoutException e) { |
| // ignore |
| } |
| this.reset(); |
| return false; |
| } |
| |
| public ServiceRegistration<?> reg; |
| } |
| } |