You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/10/18 23:24:41 UTC
[sling-org-apache-sling-hapi] 25/27: SLING-6978 [HApi] NPE if type
is fetched from cache before the end of initialization
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-hapi.git
commit 1f510cec25134676b32cbe6a45a268dc969f2e71
Author: Andrei Dulvac <du...@apache.org>
AuthorDate: Thu Jun 29 12:51:24 2017 +0000
SLING-6978 [HApi] NPE if type is fetched from cache before the end of initialization
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1800275 13f79535-47bb-0310-9956-ffa450edef68
---
src/main/java/org/apache/sling/hapi/HApiType.java | 1 +
.../org/apache/sling/hapi/impl/HApiTypeImpl.java | 5 +-
.../sling/hapi/impl/HApiTypeLazyWrapper.java | 188 +++++++++++++++++++++
.../org/apache/sling/hapi/impl/HApiUtilImpl.java | 154 +++++++++--------
4 files changed, 276 insertions(+), 72 deletions(-)
diff --git a/src/main/java/org/apache/sling/hapi/HApiType.java b/src/main/java/org/apache/sling/hapi/HApiType.java
index 0851f92..8fcdfac 100644
--- a/src/main/java/org/apache/sling/hapi/HApiType.java
+++ b/src/main/java/org/apache/sling/hapi/HApiType.java
@@ -27,6 +27,7 @@ import java.util.Map;
/**
* A Hypermedia API type.
*/
+
@ProviderType
public interface HApiType {
diff --git a/src/main/java/org/apache/sling/hapi/impl/HApiTypeImpl.java b/src/main/java/org/apache/sling/hapi/impl/HApiTypeImpl.java
index 516229b..8d6eb2c 100644
--- a/src/main/java/org/apache/sling/hapi/impl/HApiTypeImpl.java
+++ b/src/main/java/org/apache/sling/hapi/impl/HApiTypeImpl.java
@@ -23,7 +23,10 @@ import org.apache.sling.hapi.HApiType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.*;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
/**
* {@inheritDoc}
diff --git a/src/main/java/org/apache/sling/hapi/impl/HApiTypeLazyWrapper.java b/src/main/java/org/apache/sling/hapi/impl/HApiTypeLazyWrapper.java
new file mode 100644
index 0000000..62e1fe6
--- /dev/null
+++ b/src/main/java/org/apache/sling/hapi/impl/HApiTypeLazyWrapper.java
@@ -0,0 +1,188 @@
+/*******************************************************************************
+ * 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.hapi.impl;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.hapi.HApiException;
+import org.apache.sling.hapi.HApiProperty;
+import org.apache.sling.hapi.HApiType;
+import org.apache.sling.hapi.HApiUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.RepositoryException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * {@inheritDoc}
+ */
+public class HApiTypeLazyWrapper implements HApiType {
+ public static final Logger LOG = LoggerFactory.getLogger(HApiTypeLazyWrapper.class);
+ private final HApiUtil util;
+ private final ResourceResolver resolver;
+ private String serverUrl;
+ private final Resource resource;
+
+ /**
+ * A new HApiType that is just a weak reference by name
+ * @param util
+ * @param resolver
+ * @param name
+ */
+ public HApiTypeLazyWrapper(HApiUtil util, ResourceResolver resolver, String serverUrl, String name) {
+ this.util = util;
+ this.resolver = resolver;
+ this.serverUrl = serverUrl;
+ try {
+ this.resource = util.getTypeResource(resolver, name);
+ } catch (RepositoryException e) {
+ throw new HApiException("Can't find type " + name + "!", e);
+ }
+ }
+
+ public HApiTypeLazyWrapper(HApiUtil util, ResourceResolver resolver, String serverUrl, Resource resource) {
+ this.util = util;
+ this.resolver = resolver;
+ this.serverUrl = serverUrl;
+ this.resource = resource;
+ }
+ /**
+ * Load the type from the cache
+ * @return
+ */
+ private HApiType getTypeFromCache() {
+ try {
+ return TypesCache.getInstance(this.util).getType(resolver, resource);
+ } catch (RepositoryException e) {
+ String name = (null != resource) ? resource.getName() : "";
+ throw new HApiException("Can't find type " + name + "!", e);
+ }
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getName() {
+ return getTypeFromCache().getName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getDescription() {
+ return getTypeFromCache().getDescription();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getPath() {
+ return getTypeFromCache().getPath();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getUrl() {
+ return this.serverUrl + getPath() + ".html";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getFqdn() {
+ return getTypeFromCache().getFqdn();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<String> getParameters() {
+ return getTypeFromCache().getParameters();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Map<String, HApiProperty> getProperties() {
+ return getTypeFromCache().getProperties();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Map<String, HApiProperty> getAllProperties() {
+ return getAllProperties(this);
+ }
+
+ private Map<String, HApiProperty> getAllProperties(HApiType rootType) {
+ HApiType parent = getParent(rootType);
+ Map<String, HApiProperty> allProps = new HashMap<String, HApiProperty>();
+ LOG.debug("parent: {}", parent);
+ if (null != parent) {
+ Map<String, HApiProperty> parentProps;
+ if (parent instanceof HApiTypeLazyWrapper) {
+ parentProps = ((HApiTypeLazyWrapper) parent).getAllProperties(rootType);
+ } else {
+ parentProps = parent.getAllProperties();
+ }
+ LOG.debug("parent props: {}", parentProps);
+ allProps.putAll(parentProps);
+ }
+ allProps.putAll(getProperties());
+ return allProps;
+ }
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public HApiType getParent() {
+ return getTypeFromCache().getParent();
+ }
+
+ private HApiType getParent(HApiType rootType) {
+ if (this.equals(rootType)) return null;
+ return getParent();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isAbstract() {
+ return getTypeFromCache().isAbstract();
+ }
+
+ @Override
+ public String toString() {
+ return "[Weak reference] " + this.getName() + "(" + this.getPath() + "): Properties: " + this.getProperties();
+ }
+}
diff --git a/src/main/java/org/apache/sling/hapi/impl/HApiUtilImpl.java b/src/main/java/org/apache/sling/hapi/impl/HApiUtilImpl.java
index a140713..f1ae6e9 100644
--- a/src/main/java/org/apache/sling/hapi/impl/HApiUtilImpl.java
+++ b/src/main/java/org/apache/sling/hapi/impl/HApiUtilImpl.java
@@ -34,44 +34,72 @@ import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;
import javax.jcr.query.QueryResult;
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Property;
-import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;
-import org.apache.sling.commons.osgi.PropertiesUtil;
import org.apache.sling.hapi.*;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.AttributeType;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-@Component(label = "Apache Sling Hypermedia API tools", metatype = true)
-@Service(value = HApiUtil.class)
+@Component(
+ name = "Apache Sling Hypermedia API tools",
+ service = HApiUtil.class,
+ configurationPid = "org.apache.sling.hapi.impl.HApiUtilImpl"
+)
+@Designate(
+ ocd = HApiUtilImpl.Configuration.class
+)
public class HApiUtilImpl implements HApiUtil {
private final Logger LOG = LoggerFactory.getLogger(HApiUtil.class);
- @Property(label = "HApi Resource Type", cardinality = 0, value = DEFAULT_RESOURCE_TYPE,
- description = RESOURCE_TYPE_DESC)
- public static final String HAPI_RESOURCE_TYPE = RESOURCE_TYPE;
+ @ObjectClassDefinition(
+ name = "Apache Sling Hypermedia API tools"
+ )
+ @interface Configuration {
- @Property(label = "HApi Collection Resource Type", cardinality = 0, value = DEFAULT_COLLECTION_RESOURCE_TYPE,
- description = COLLECTION_RESOURCE_TYPE_DESC)
- private static final String HAPI_COLLECTION_RESOURCE_TYPE = COLLECTION_RESOURCE_TYPE;
+ @AttributeDefinition(
+ name = "HApi Resource Type",
+ description = RESOURCE_TYPE_DESC
- @Property(label = "HApi Types Search Paths", cardinality=50, value = {DEFAULT_SEARCH_PATH},
- description = SEARCH_PATHS_DESC)
- public static final String HAPI_PATHS = SEARCH_PATHS;
+ )
+ String org_apache_sling_hapi_tools_resourcetype() default DEFAULT_RESOURCE_TYPE;
- @Property(label = "External server URL", cardinality = 0, value = DEFAULT_SERVER_URL,
- description = EXTERNAL_URL_DESC)
- public static final String HAPI_EXTERNAL_URL = EXTERNAL_URL;
+ @AttributeDefinition(
+ name = "HApi Collection Resource Type",
+ description = COLLECTION_RESOURCE_TYPE_DESC
- @Property(label = "Enabled", boolValue = DEFAULT_ENABLED,
- description = ENABLED_DESC)
- public static final String HAPI_ENABLED = ENABLED;
+ )
+ String org_apache_sling_hapi_tools_collectionresourcetype() default DEFAULT_COLLECTION_RESOURCE_TYPE;
+
+ @AttributeDefinition(
+ name = "HApi Types Search Paths",
+ description = SEARCH_PATHS_DESC
+ )
+ String[] org_apache_sling_hapi_tools_searchpaths() default {DEFAULT_SEARCH_PATH};
+
+ @AttributeDefinition(
+ name = "External server URL",
+ description = EXTERNAL_URL_DESC
+
+ )
+ String org_apache_sling_hapi_tools_externalurl() default DEFAULT_SERVER_URL;
+
+ @AttributeDefinition(
+ name = "Enabled",
+ description = ENABLED_DESC,
+ type = AttributeType.BOOLEAN
+ )
+ boolean org_apache_sling_hapi_tools_enabled() default DEFAULT_ENABLED;
+
+ }
private static String resourceType;
@@ -82,15 +110,14 @@ public class HApiUtilImpl implements HApiUtil {
@Activate
- private void activate(Map<String, Object> configuration) {
- enabled = PropertiesUtil.toBoolean(configuration.get(HAPI_ENABLED), false);
+ private void activate(HApiUtilImpl.Configuration configuration) {
+ enabled = configuration.org_apache_sling_hapi_tools_enabled();
if (!enabled) return;
- resourceType = PropertiesUtil.toString(configuration.get(HAPI_RESOURCE_TYPE), DEFAULT_RESOURCE_TYPE);
- collectionResourceType = PropertiesUtil.toString(configuration.get(HAPI_COLLECTION_RESOURCE_TYPE),
- DEFAULT_COLLECTION_RESOURCE_TYPE);
- hApiPaths = PropertiesUtil.toStringArray(configuration.get(HAPI_PATHS));
- serverContextPath = PropertiesUtil.toString(configuration.get(HAPI_EXTERNAL_URL), DEFAULT_SERVER_URL);
+ resourceType = configuration.org_apache_sling_hapi_tools_resourcetype();
+ collectionResourceType = configuration.org_apache_sling_hapi_tools_collectionresourcetype();
+ hApiPaths = configuration.org_apache_sling_hapi_tools_searchpaths();
+ serverContextPath = configuration.org_apache_sling_hapi_tools_externalurl();
}
/**
@@ -221,51 +248,36 @@ public class HApiUtilImpl implements HApiUtil {
for (Value p : Arrays.asList(parameterValues)) {
parameters.add(p.getString());
}
- HApiTypeImpl newType = new HApiTypeImpl(name, description, serverContextPath, path, fqdn, parameters, null, null, false);
- TypesCache.getInstance(this).addType(newType);
- LOG.debug("Inserted type {} to cache: {}", newType, TypesCache.getInstance(this));
-
- try {
- // Get parent if it exists
- HApiType parent = null;
- String parentPath = resProps.get("extends", (String) null);
- if (null != parentPath) {
- parent = TypesCache.getInstance(this).getType(resolver, getTypeResource(resolver, parentPath));
- }
-
- // Get properties
- Map<String, HApiProperty> properties = new HashMap<String, HApiProperty>();
- for (Resource res : typeResource.getChildren()) {
- ValueMap resValueMap = res.adaptTo(ValueMap.class);
-
- String propName = res.getName();
- String propDescription = resValueMap.get("description", "");
- String typeFqdnOrPath = resValueMap.get("type", (String) null);
- Resource propTypeResource = getTypeResource(resolver, typeFqdnOrPath);
- HApiType propType = (null != propTypeResource)
- ? TypesCache.getInstance(this).getType(resolver, propTypeResource)
- : new AbstractHapiTypeImpl(typeFqdnOrPath);
- LOG.debug("Fetched type {} from cache", propType);
- Boolean propMultiple = resValueMap.get("multiple", false);
-
- HApiProperty prop = new HApiPropertyImpl(propName, propDescription, propType, propMultiple);
- properties.put(prop.getName(), prop);
- }
- // Set parent and properties
- newType.setParent(parent);
- newType.setProperties(properties);
-
- } catch (RuntimeException t) {
- // Remove type from cache if it wasn't created successfully
- TypesCache.getInstance(this).removeType(newType.getPath());
- throw t;
- } catch (RepositoryException e) {
- // Remove type from cache if it wasn't created successfully
- TypesCache.getInstance(this).removeType(newType.getPath());
- throw e;
+ // Parent weak reference
+ String parentPath = resProps.get("extends", (String) null);
+ HApiType parentWeak = new HApiTypeLazyWrapper(this, resolver, this.serverContextPath, parentPath);
+
+ // Properties weak reference
+ Map<String, HApiProperty> properties = new HashMap<String, HApiProperty>();
+ for (Resource res : typeResource.getChildren()) {
+ ValueMap resValueMap = res.adaptTo(ValueMap.class);
+
+ String propName = res.getName();
+ String propDescription = resValueMap.get("description", "");
+ String typeFqdnOrPath = resValueMap.get("type", (String) null);
+ Resource propTypeResource = getTypeResource(resolver, typeFqdnOrPath);
+ HApiType propTypeWeak = (null != propTypeResource)
+ ? new HApiTypeLazyWrapper(this, resolver, this.serverContextPath, propTypeResource)
+ : new AbstractHapiTypeImpl(typeFqdnOrPath);
+ Boolean propMultiple = resValueMap.get("multiple", false);
+
+ HApiProperty prop = new HApiPropertyImpl(propName, propDescription, propTypeWeak, propMultiple);
+ properties.put(prop.getName(), prop);
}
+ //
+ // Create type and add to cache
+ //
+ HApiTypeImpl newType = new HApiTypeImpl(name, description, serverContextPath, path, fqdn, parameters, properties, parentWeak, false);
+ TypesCache.getInstance(this).addType(newType);
+ LOG.debug("Inserted type {} to cache: {}", newType, TypesCache.getInstance(this));
+
LOG.debug("Created type {}", newType);
return newType;
}
--
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.