blob: 9b81137535f0af40c084d011d798feea2184b17f [file] [log] [blame]
/*
* 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.felix.http.base.internal.service;
import static java.util.Collections.list;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.felix.http.base.internal.registry.HandlerRegistry;
import org.apache.felix.http.base.internal.runtime.dto.RequestInfoDTOBuilder;
import org.apache.felix.http.base.internal.runtime.dto.RuntimeDTOBuilder;
import org.apache.felix.http.base.internal.whiteboard.WhiteboardManager;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.dto.ServiceReferenceDTO;
import org.osgi.service.http.runtime.HttpServiceRuntime;
import org.osgi.service.http.runtime.dto.RequestInfoDTO;
import org.osgi.service.http.runtime.dto.RuntimeDTO;
public final class HttpServiceRuntimeImpl implements HttpServiceRuntime
{
/**
* Service property for change count. This constant is defined here to avoid
* a dependency on R7 of the framework.
* The value of the property is of type {@code Long}.
*/
private static final String PROP_CHANGECOUNT = "service.changecount";
private static final String PROP_CHANGECOUNTDELAY = "org.apache.felix.http.whiteboard.changecount.delay";
private volatile Hashtable<String, Object> attributes = new Hashtable<>();
private final HandlerRegistry registry;
private final WhiteboardManager contextManager;
private volatile long changeCount;
private volatile ServiceRegistration<HttpServiceRuntime> serviceReg;
private volatile ServiceReferenceDTO serviceRefDTO;
private volatile Timer timer;
private final long updateChangeCountDelay;
public HttpServiceRuntimeImpl(HandlerRegistry registry,
WhiteboardManager contextManager,
BundleContext bundleContext)
{
this.registry = registry;
this.contextManager = contextManager;
final Object val = bundleContext.getProperty(PROP_CHANGECOUNTDELAY);
long value = 2000L;
if ( val != null )
{
try
{
value = Long.parseLong(val.toString());
}
catch ( final NumberFormatException nfe)
{
// ignore
}
if ( value < 1 )
{
value = 0L;
}
}
updateChangeCountDelay = value;
}
@Override
public RuntimeDTO getRuntimeDTO()
{
if ( this.serviceRefDTO == null )
{
// it might happen that this code is executed in several threads
// but that's very unlikely and even if, fetching the service
// reference several times is not a big deal
final ServiceRegistration<HttpServiceRuntime> reg = this.serviceReg;
if ( reg != null )
{
final long id = (long) reg.getReference().getProperty(Constants.SERVICE_ID);
final ServiceReferenceDTO[] dtos = reg.getReference().getBundle().adapt(ServiceReferenceDTO[].class);
for(final ServiceReferenceDTO dto : dtos)
{
if ( dto.id == id)
{
this.serviceRefDTO = dto;
break;
}
}
}
}
if ( this.serviceRefDTO != null )
{
final RuntimeDTOBuilder runtimeDTOBuilder = new RuntimeDTOBuilder(contextManager.getRuntimeInfo(),
this.serviceRefDTO);
return runtimeDTOBuilder.build();
}
throw new IllegalStateException("Service is already unregistered");
}
@Override
public RequestInfoDTO calculateRequestInfoDTO(final String path)
{
return new RequestInfoDTOBuilder(registry, path).build();
}
public synchronized void setAttribute(String name, Object value)
{
Hashtable<String, Object> newAttributes = new Hashtable<>(attributes);
newAttributes.put(name, value);
attributes = newAttributes;
}
public synchronized void setAllAttributes(Dictionary<String, Object> newAttributes)
{
Hashtable<String, Object> replacement = new Hashtable<>();
for (String key : list(newAttributes.keys()))
{
replacement.put(key, newAttributes.get(key));
}
replacement.put(PROP_CHANGECOUNT, this.changeCount);
attributes = replacement;
}
public void register(final BundleContext bundleContext)
{
this.serviceReg = bundleContext.registerService(HttpServiceRuntime.class,
this,
attributes);
}
public void unregister()
{
if ( this.serviceReg != null )
{
try
{
this.serviceReg.unregister();
}
catch ( final IllegalStateException ise)
{
// we just ignore it
}
this.serviceReg = null;
}
this.serviceRefDTO = null;
}
public ServiceReference<HttpServiceRuntime> getServiceReference()
{
final ServiceRegistration<HttpServiceRuntime> reg = this.serviceReg;
if ( reg != null )
{
return reg.getReference();
}
return null;
}
public void updateChangeCount()
{
final ServiceRegistration<HttpServiceRuntime> reg = this.serviceReg;
if ( reg != null )
{
boolean setPropsDirectly = false;
synchronized ( this )
{
this.changeCount++;
final long count = this.changeCount;
this.setAttribute(PROP_CHANGECOUNT, this.changeCount);
if ( this.updateChangeCountDelay <= 0L )
{
setPropsDirectly = true;
}
else
{
if ( this.timer == null )
{
this.timer = new Timer();
}
timer.schedule(new TimerTask()
{
@Override
public void run()
{
synchronized ( HttpServiceRuntimeImpl.this )
{
if ( changeCount == count )
{
try
{
reg.setProperties(attributes);
}
catch ( final IllegalStateException ise)
{
// we ignore this as this might happen on shutdown
}
timer.cancel();
timer = null;
}
}
}
}, this.updateChangeCountDelay);
}
}
if ( setPropsDirectly )
{
try
{
reg.setProperties(attributes);
}
catch ( final IllegalStateException ise)
{
// we ignore this as this might happen on shutdown
}
}
}
}
}