You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by dk...@apache.org on 2018/10/08 03:00:46 UTC
[sling-org-apache-sling-app-cms] 01/01: Adding the initial code for
displaying insights in Sling CMS
This is an automated email from the ASF dual-hosted git repository.
dklco pushed a commit to branch insights-feature
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-app-cms.git
commit 652210b67d11d2b2a91912b4e8853083869b56c8
Author: Dan Klco <dk...@apache.org>
AuthorDate: Sun Oct 7 23:00:32 2018 -0400
Adding the initial code for displaying insights in Sling CMS
---
api/pom.xml | 23 +-
api/src/main/java/org/apache/sling/cms/File.java | 138 ++++++++++
.../java/org/apache/sling/cms/FileManager.java | 34 +++
.../sling/cms/insights/FileInsightRequest.java | 39 +++
.../org/apache/sling/cms/insights/Insight.java | 164 ++++++++++++
.../apache/sling/cms/insights/InsightFactory.java | 48 ++++
.../apache/sling/cms/insights/InsightProvider.java | 56 ++++
.../apache/sling/cms/insights/InsightRequest.java | 45 ++++
.../org/apache/sling/cms/insights/Message.java | 67 +++++
.../sling/cms/insights/PageInsightRequest.java | 67 +++++
.../apache/sling/cms/insights/package-info.java | 25 ++
core/pom.xml | 4 +
.../ipeirotis/readability/engine/Readability.java | 231 ++++++++++++++++
.../readability/engine/SentenceExtractor.java | 48 ++++
.../ipeirotis/readability/engine/Syllabify.java | 73 +++++
.../core/insights/impl/BaseInsightProvider.java | 63 +++++
.../cms/core/insights/impl/FakeHttpSession.java | 101 +++++++
.../sling/cms/core/insights/impl/FakeRequest.java | 298 +++++++++++++++++++++
.../sling/cms/core/insights/impl/FakeResponse.java | 189 +++++++++++++
.../core/insights/impl/FileInsightRequestImpl.java | 46 ++++
.../cms/core/insights/impl/InsightFactoryImpl.java | 98 +++++++
.../core/insights/impl/PageInsightRequestImpl.java | 107 ++++++++
.../insights/impl/ReadabilityInsightProvider.java | 5 +
.../models/{PageImpl.java => FileImpl.java} | 102 +++----
.../cms/core/internal/models/FileManagerImpl.java | 47 ++++
.../sling/cms/core/internal/models/PageImpl.java | 8 +-
pom.xml | 6 +
27 files changed, 2045 insertions(+), 87 deletions(-)
diff --git a/api/pom.xml b/api/pom.xml
index eb7c0c0..64efe15 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -1,15 +1,12 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
-<!-- 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. -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<!-- 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. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
+>
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>org.apache.sling.cms</artifactId>
@@ -95,5 +92,9 @@
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.jsoup</groupId>
+ <artifactId>jsoup</artifactId>
+ </dependency>
</dependencies>
</project>
\ No newline at end of file
diff --git a/api/src/main/java/org/apache/sling/cms/File.java b/api/src/main/java/org/apache/sling/cms/File.java
new file mode 100644
index 0000000..d08c331
--- /dev/null
+++ b/api/src/main/java/org/apache/sling/cms/File.java
@@ -0,0 +1,138 @@
+/*
+ * 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.cms;
+
+import java.util.Calendar;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ValueMap;
+import org.osgi.annotation.versioning.ProviderType;
+
+/**
+ * An interface representing a sling:File resource. Adaptable from a sling:File
+ * Resource.
+ */
+@ProviderType
+public interface File {
+
+ /**
+ * Gets the path of this file after it is published on the site's primary domain
+ * with the the html extension
+ *
+ * @return the published path of the file
+ */
+ String getPublishedPath();
+
+ /**
+ * Gets the full url (including domain) of this file after it is published on
+ * the site's primary domain
+ *
+ * @return the published url of the file
+ */
+ String getPublishedUrl();
+
+ /**
+ * Gets the site this file is contained within
+ *
+ * @return the site containing the file
+ */
+ Site getSite();
+
+ /**
+ * Retrieves the content Resource of the file
+ *
+ * @return the jcr:content child resource of the file
+ */
+ Resource getContentResource();
+
+ /**
+ * Gets the date the file was created
+ *
+ * @return the date on which the file was created
+ */
+ Calendar getCreated();
+
+ /**
+ * Gets the name of the user whom created this file
+ *
+ * @return the name of the user whom created the file
+ */
+ String getCreatedBy();
+
+ /**
+ * Gets the last time this file was modified
+ *
+ * @return the date the file was last modified
+ */
+ Calendar getLastModified();
+
+ /**
+ * Gets the username of the user who last modified the file
+ *
+ * @return the name of the user who last modified the file
+ */
+ String getLastModifiedBy();
+
+ /**
+ * Gets the name of the Sling Resource backing the file
+ *
+ * @return the name of the file resource
+ */
+ String getName();
+
+ /**
+ * Gets the parent of the current file
+ *
+ * @return the parent of the file
+ */
+ Resource getParent();
+
+ /**
+ * Get the path this file resides within the repository
+ *
+ * @return the path of the file
+ */
+ String getPath();
+
+ /**
+ * Gets a ValueMap of the properties of the content resource for this page
+ *
+ * @return the properties of the content resource
+ */
+ ValueMap getProperties();
+
+ /**
+ * Returns true if the file is published, false otherwise
+ *
+ * @return whether or not the file is published
+ */
+ boolean isPublished();
+
+ /**
+ * Gets the resource backing this file
+ *
+ * @return the resource backing the file
+ */
+ Resource getResource();
+
+ /**
+ * Gets the content type of this file
+ *
+ * @return the content type of the file
+ */
+ String getContentType();
+}
diff --git a/api/src/main/java/org/apache/sling/cms/FileManager.java b/api/src/main/java/org/apache/sling/cms/FileManager.java
new file mode 100644
index 0000000..f322dd7
--- /dev/null
+++ b/api/src/main/java/org/apache/sling/cms/FileManager.java
@@ -0,0 +1,34 @@
+/*
+ * 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.cms;
+
+import org.osgi.annotation.versioning.ProviderType;
+
+/**
+ * A interface used to retrieve sling:File Resources. Adaptable from a child
+ * Resource of a sling:File.
+ */
+@ProviderType
+public interface FileManager {
+
+ /**
+ * Get the file containing the adapted resource
+ *
+ * @return the file
+ */
+ File getFile();
+}
diff --git a/api/src/main/java/org/apache/sling/cms/insights/FileInsightRequest.java b/api/src/main/java/org/apache/sling/cms/insights/FileInsightRequest.java
new file mode 100644
index 0000000..f45a8f7
--- /dev/null
+++ b/api/src/main/java/org/apache/sling/cms/insights/FileInsightRequest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.cms.insights;
+
+import org.apache.sling.cms.File;
+
+/**
+ * Represents an insight request for a file
+ */
+public interface FileInsightRequest extends InsightRequest {
+
+ public default TYPE getType() {
+ return TYPE.FILE;
+ }
+
+ /**
+ * Returns the file used to create this request
+ *
+ * @return the file
+ */
+ public File getFile();
+
+}
diff --git a/api/src/main/java/org/apache/sling/cms/insights/Insight.java b/api/src/main/java/org/apache/sling/cms/insights/Insight.java
new file mode 100644
index 0000000..eefbb8d
--- /dev/null
+++ b/api/src/main/java/org/apache/sling/cms/insights/Insight.java
@@ -0,0 +1,164 @@
+/*
+ * 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.cms.insights;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Simple POJO Model for holding an insight provider's results.
+ */
+public class Insight {
+
+ private Object data;
+ private boolean display = true;
+ private InsightProvider provider;
+ private InsightRequest request;
+ private double score;
+ private boolean scored = false;
+ private List<Message> scoreDetails = new ArrayList<>();
+ private boolean skip = false;
+ private boolean succeeded = true;
+
+ public Insight(InsightProvider provider, InsightRequest request) {
+ this.request = request;
+ this.provider = provider;
+ }
+
+ /**
+ * @return the data
+ */
+ public Object getData() {
+ return data;
+ }
+
+ /**
+ * @return the provider
+ */
+ public InsightProvider getProvider() {
+ return provider;
+ }
+
+ /**
+ * @return the request
+ */
+ public InsightRequest getRequest() {
+ return request;
+ }
+
+ /**
+ * @return the score
+ */
+ public double getScore() {
+ return score;
+ }
+
+ /**
+ * @return the scoreDetails
+ */
+ public List<Message> getScoreDetails() {
+ return scoreDetails;
+ }
+
+ /**
+ * @return the display
+ */
+ public boolean isDisplay() {
+ return display;
+ }
+
+ public boolean isScored() {
+ return scored;
+ }
+
+ /**
+ * @return the skip
+ */
+ public boolean isSkip() {
+ return skip;
+ }
+
+ /**
+ * @return the succeeded
+ */
+ public boolean isSucceeded() {
+ return succeeded;
+ }
+
+ /**
+ * @param data the data to set
+ */
+ public void setData(Object data) {
+ this.data = data;
+ }
+
+ /**
+ * @param display the display to set
+ */
+ public void setDisplay(boolean display) {
+ this.display = display;
+ }
+
+ /**
+ * @param provider the provider to set
+ */
+ public void setProvider(InsightProvider provider) {
+ this.provider = provider;
+ }
+
+ /**
+ * @param request the request to set
+ */
+ public void setRequest(InsightRequest request) {
+ this.request = request;
+ }
+
+ /**
+ * @param score the score to set
+ */
+ public void setScore(double score) {
+ this.score = score;
+ }
+
+ public void setScored(boolean scored) {
+ this.scored = scored;
+ }
+
+ /**
+ * @param scoreDetails the scoreDetails to set
+ */
+ public void setScoreDetails(List<Message> scoreDetails) {
+ this.scoreDetails = scoreDetails;
+ }
+
+ /**
+ * @param skip the skip to set
+ */
+ public void setSkip(boolean skip) {
+ this.skip = skip;
+ }
+
+ /**
+ * @param succeeded the succeeded to set
+ */
+ public void setSucceeded(boolean succeeded) {
+ this.succeeded = succeeded;
+ }
+
+}
diff --git a/api/src/main/java/org/apache/sling/cms/insights/InsightFactory.java b/api/src/main/java/org/apache/sling/cms/insights/InsightFactory.java
new file mode 100644
index 0000000..f7d2e9b
--- /dev/null
+++ b/api/src/main/java/org/apache/sling/cms/insights/InsightFactory.java
@@ -0,0 +1,48 @@
+/*
+ * 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.cms.insights;
+
+import java.util.Collection;
+
+import org.apache.sling.cms.File;
+import org.apache.sling.cms.Page;
+
+/**
+ * Service Factory for retrieving insight instances.
+ */
+public interface InsightFactory {
+
+ /**
+ * Get the insights which are enabled for a particular file.
+ *
+ * @param file the file for which to retrieve the insights
+ * @return the insights
+ */
+ Collection<Insight> getInsights(File file);
+
+
+ /**
+ * Get the insights which are enabled for a particular page.
+ *
+ * @param page the page for which to retrieve the insights
+ * @return the insights
+ */
+ Collection<Insight> getInsights(Page page);
+
+}
diff --git a/api/src/main/java/org/apache/sling/cms/insights/InsightProvider.java b/api/src/main/java/org/apache/sling/cms/insights/InsightProvider.java
new file mode 100644
index 0000000..baa5f4e
--- /dev/null
+++ b/api/src/main/java/org/apache/sling/cms/insights/InsightProvider.java
@@ -0,0 +1,56 @@
+/*
+ * 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.cms.insights;
+
+/**
+ * Interface for all of the Insight Provider services to implement.
+ */
+public interface InsightProvider {
+
+ /**
+ * Evaluate the request and return a response with the details.
+ *
+ * @param request the request to evaluate
+ * @return the insights gathered
+ */
+ Insight evaluateRequest(InsightRequest request);
+
+ /**
+ * Get the ID for a particular Insight Provider. This should be human readable
+ * and URL-safe.
+ *
+ * @return the check ID
+ */
+ String getId();
+
+ /**
+ * The title of the Insight Provider
+ *
+ * @return the user-displayed title
+ */
+ String getTitle();
+
+ /**
+ * Returns true if the provider is enabled for this request and false otherwise.
+ *
+ * @param request the request to evaluate
+ * @return true if enabled, false otherwise
+ */
+ boolean isEnabled(InsightRequest request);
+}
diff --git a/api/src/main/java/org/apache/sling/cms/insights/InsightRequest.java b/api/src/main/java/org/apache/sling/cms/insights/InsightRequest.java
new file mode 100644
index 0000000..bd310a9
--- /dev/null
+++ b/api/src/main/java/org/apache/sling/cms/insights/InsightRequest.java
@@ -0,0 +1,45 @@
+/*
+ * 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.cms.insights;
+
+import org.apache.sling.api.resource.Resource;
+
+/**
+ * Represents an insight request
+ */
+public interface InsightRequest {
+
+ public enum TYPE {
+ FILE, PAGE
+ }
+
+ /**
+ * Gets the resource used to create this request.
+ *
+ * @return
+ */
+ Resource getResource();
+
+ /**
+ * Get the type of this request.
+ *
+ * @return the type
+ */
+ TYPE getType();
+}
diff --git a/api/src/main/java/org/apache/sling/cms/insights/Message.java b/api/src/main/java/org/apache/sling/cms/insights/Message.java
new file mode 100644
index 0000000..ff51cbb
--- /dev/null
+++ b/api/src/main/java/org/apache/sling/cms/insights/Message.java
@@ -0,0 +1,67 @@
+/*
+ * 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.cms.insights;
+
+/**
+ * Represents a message which may be assigned a status and text
+ */
+public class Message {
+
+ public enum STYLE {
+ DEFAULT, DANGER, WARN, SUCCESS
+ }
+
+ private STYLE style;
+
+ private String text;
+
+ public Message(String text, STYLE style) {
+ this.text = text;
+ this.style = style;
+ }
+
+ public STYLE getStyle() {
+ return style;
+ }
+
+ public String getStyleClass() {
+ String styleClass = "";
+ if (style != STYLE.DEFAULT) {
+ styleClass = "text-" + style.toString().toLowerCase();
+ }
+ return styleClass;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setStyle(STYLE style) {
+ this.style = style;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ @Override
+ public String toString() {
+ return "Message [style=" + style + ", text=" + text + "]";
+ }
+}
diff --git a/api/src/main/java/org/apache/sling/cms/insights/PageInsightRequest.java b/api/src/main/java/org/apache/sling/cms/insights/PageInsightRequest.java
new file mode 100644
index 0000000..6a8054c
--- /dev/null
+++ b/api/src/main/java/org/apache/sling/cms/insights/PageInsightRequest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.cms.insights;
+
+import java.io.IOException;
+
+import org.apache.sling.cms.Page;
+import org.jsoup.nodes.Document;
+
+/**
+ * Represents an insight request
+ */
+public interface PageInsightRequest extends InsightRequest {
+
+ /**
+ * Gets the page backing this request
+ *
+ * @return the page
+ */
+ public Page getPage();
+
+ /**
+ * Gets the HTML of the body of the page, not the full page (e.g. no header).
+ *
+ * @return the HTML of the body
+ * @throws IOException an exception occurs retrieving the content
+ */
+ public String getPageBodyHtml() throws IOException;
+
+ /**
+ * Gets the page HTML as a JSoup Document.
+ *
+ * @return the page HTML
+ * @throws IOException an exception occurs retrieving the content
+ */
+ public Document getPageDocument() throws IOException;
+
+ /**
+ * Gets the page HTML. Loads the HTML lazily so the initial request may take a
+ * bit but others will be quick.
+ *
+ * @return a string representation of the HTML for a page
+ * @throws ServletException
+ * @throws IOException
+ */
+ public String getPageHtml() throws IOException;
+
+ public default TYPE getType() {
+ return TYPE.PAGE;
+ }
+}
diff --git a/api/src/main/java/org/apache/sling/cms/insights/package-info.java b/api/src/main/java/org/apache/sling/cms/insights/package-info.java
new file mode 100644
index 0000000..07fd7d0
--- /dev/null
+++ b/api/src/main/java/org/apache/sling/cms/insights/package-info.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+/**
+ * Support for Content Insights
+ *
+ * @version 0.10.2
+ */
+package org.apache.sling.cms.insights;
\ No newline at end of file
diff --git a/core/pom.xml b/core/pom.xml
index 640e9f2..5e04613 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -186,5 +186,9 @@
<groupId>org.apache.jackrabbit</groupId>
<artifactId>oak-core</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.jsoup</groupId>
+ <artifactId>jsoup</artifactId>
+ </dependency>
</dependencies>
</project>
\ No newline at end of file
diff --git a/core/src/main/java/com/ipeirotis/readability/engine/Readability.java b/core/src/main/java/com/ipeirotis/readability/engine/Readability.java
new file mode 100644
index 0000000..9a639d9
--- /dev/null
+++ b/core/src/main/java/com/ipeirotis/readability/engine/Readability.java
@@ -0,0 +1,231 @@
+package com.ipeirotis.readability.engine;
+
+import java.math.BigDecimal;
+
+
+/**
+ * Implements various readability indexes
+ *
+ * @author Panos Ipeirotis
+ *
+ */
+public class Readability {
+
+ private static SentenceExtractor se = new SentenceExtractor();
+
+ Integer sentences;
+
+ Integer complex;
+
+ Integer words;
+
+ Integer syllables;
+
+ Integer characters;
+
+
+ public Readability(String text) {
+
+ // We add the "." for the sentence extractor to pick the last sentence,
+ // if it does not end with a punctuation mark.
+ this.sentences = getNumberOfSentences(text + ".");
+ this.complex = getNumberOfComplexWords(text);
+ this.words = getNumberOfWords(text);
+ this.syllables = getNumberOfSyllables(text);
+ this.characters = getNumberOfCharacters(text);
+
+ }
+
+ /**
+ * Returns true is the word contains 3 or more syllables
+ *
+ * @param w
+ * @return
+ */
+ public static boolean isComplex(String w) {
+ int syllables = Syllabify.syllable(w);
+ return (syllables > 2);
+ }
+
+ /**
+ * Returns the number of letter characters in the text
+ *
+ * @return
+ */
+ public static int getNumberOfCharacters(String text) {
+ String cleanText = cleanLine(text);
+ String[] word = cleanText.split(" ");
+
+ int characters = 0;
+ for (String w : word) {
+ characters += w.length();
+ }
+ return characters;
+ }
+
+ /**
+ * Returns the number of words with 3 or more syllables
+ *
+ * @param text
+ * @return the number of words in the text with 3 or more syllables
+ */
+ public static int getNumberOfComplexWords(String text) {
+ String cleanText = cleanLine(text);
+ String[] words = cleanText.split(" ");
+ int complex = 0;
+ for (String w : words) {
+ if (isComplex(w))
+ complex++;
+ }
+ return complex;
+ }
+
+ public static int getNumberOfWords(String text) {
+ String cleanText = cleanLine(text);
+ String[] word = cleanText.split(" ");
+ int words = 0;
+ for (String w : word) {
+ if (w.length() > 0)
+ words++;
+ }
+ return words;
+ }
+
+ /**
+ * Returns the total number of syllables in the words of the text
+ *
+ * @param text
+ * @return the total number of syllables in the words of the text
+ */
+ public static int getNumberOfSyllables(String text) {
+ String cleanText = cleanLine(text);
+ String[] word = cleanText.split(" ");
+ int syllables = 0;
+ for (String w : word) {
+ if (w.length() > 0) {
+ syllables += Syllabify.syllable(w);
+ }
+ }
+ return syllables;
+ }
+
+ private static String cleanLine(String line) {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < line.length(); i++) {
+ char c = line.charAt(i);
+ if (c < 128 && Character.isLetter(c)) {
+ buffer.append(c);
+ } else {
+ buffer.append(' ');
+ }
+ }
+ return buffer.toString().toLowerCase();
+ }
+
+ public static int getNumberOfSentences(String text) {
+ int l = se.getSentences(text).length;
+ if (l > 0)
+ return l;
+ else if (text.length() > 0)
+ return 1;
+ else
+ return 0;
+ }
+
+ /**
+ *
+ * http://en.wikipedia.org/wiki/SMOG_Index
+ *
+ * @param text
+ * @return The SMOG index of the text
+ */
+ public double getSMOGIndex() {
+ double score = Math.sqrt(complex * (30.0 / sentences)) + 3;
+ return round(score, 3);
+ }
+
+ /**
+ *
+ * http://en.wikipedia.org/wiki/SMOG
+ *
+ * @param text
+ * @return Retugns the SMOG value for the text
+ */
+ public double getSMOG() {
+ double score = 1.043 * Math.sqrt(complex * (30.0 / sentences)) + 3.1291;
+ return round(score, 3);
+ }
+
+ /**
+ *
+ * http://en.wikipedia.org/wiki/Flesch-Kincaid_Readability_Test
+ *
+ * @param text
+ * @return Returns the Flesch_Reading Ease value for the text
+ */
+ public double getFleschReadingEase() {
+
+ double score = 206.835 - 1.015 * words / sentences - 84.6 * syllables
+ / words;
+
+ return round(score, 3);
+ }
+
+ /**
+ *
+ * http://en.wikipedia.org/wiki/Flesch-Kincaid_Readability_Test
+ *
+ * @param text
+ * @return Returns the Flesch-Kincaid_Readability_Test value for the text
+ */
+ public double getFleschKincaidGradeLevel() {
+ double score = 0.39 * words / sentences + 11.8 * syllables / words
+ - 15.59;
+ return round(score, 3);
+ }
+
+ /**
+ *
+ * http://en.wikipedia.org/wiki/Automated_Readability_Index
+ *
+ * @param text
+ * @return the Automated Readability Index for text
+ */
+ public double getARI() {
+ double score = 4.71 * characters / words + 0.5 * words / sentences
+ - 21.43;
+ return round(score, 3);
+ }
+
+ /**
+ *
+ * http://en.wikipedia.org/wiki/Gunning-Fog_Index
+ *
+ * @param text
+ * @return the Gunning-Fog Index for text
+ */
+ public double getGunningFog() {
+ double score = 0.4 * (words / sentences + 100 * complex / words);
+ return round(score, 3);
+ }
+
+ /**
+ *
+ * http://en.wikipedia.org/wiki/Coleman-Liau_Index
+ *
+ * @return The Coleman-Liau_Index value for the text
+ */
+ public double getColemanLiau() {
+ double score = (5.89 * characters / words) - (30 * sentences / words)
+ - 15.8;
+ return round(score, 3);
+ }
+
+ private static Double round(double d, int decimalPlace) {
+ // see the Javadoc about why we use a String in the constructor
+ // http://java.sun.com/j2se/1.5.0/docs/api/java/math/BigDecimal.html#BigDecimal(double)
+ BigDecimal bd = new BigDecimal(Double.toString(d));
+ bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP);
+ return bd.doubleValue();
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ipeirotis/readability/engine/SentenceExtractor.java b/core/src/main/java/com/ipeirotis/readability/engine/SentenceExtractor.java
new file mode 100644
index 0000000..33fd722
--- /dev/null
+++ b/core/src/main/java/com/ipeirotis/readability/engine/SentenceExtractor.java
@@ -0,0 +1,48 @@
+package com.ipeirotis.readability.engine;
+
+import java.util.ArrayList;
+
+import com.aliasi.sentences.IndoEuropeanSentenceModel;
+import com.aliasi.sentences.SentenceModel;
+import com.aliasi.tokenizer.IndoEuropeanTokenizerFactory;
+import com.aliasi.tokenizer.Tokenizer;
+import com.aliasi.tokenizer.TokenizerFactory;
+
+/** Use SentenceModel to find sentence boundaries in text */
+public class SentenceExtractor {
+
+ final TokenizerFactory TOKENIZER_FACTORY = new IndoEuropeanTokenizerFactory();
+ final SentenceModel SENTENCE_MODEL = new IndoEuropeanSentenceModel();
+
+ public String[] getSentences(String text) {
+ ArrayList<String> tokenList = new ArrayList<String>();
+ ArrayList<String> whiteList = new ArrayList<String>();
+ Tokenizer tokenizer = TOKENIZER_FACTORY.tokenizer(text.toCharArray(), 0, text.length());
+ tokenizer.tokenize(tokenList, whiteList);
+
+ String[] tokens = new String[tokenList.size()];
+ String[] whites = new String[whiteList.size()];
+ tokenList.toArray(tokens);
+ whiteList.toArray(whites);
+ int[] sentenceBoundaries = SENTENCE_MODEL.boundaryIndices(tokens, whites);
+
+ if (sentenceBoundaries.length < 1) {
+ return new String[0];
+ }
+
+ String[] result = new String[sentenceBoundaries.length];
+
+ int sentStartTok = 0;
+ int sentEndTok = 0;
+ for (int i = 0; i < sentenceBoundaries.length; ++i) {
+ sentEndTok = sentenceBoundaries[i];
+ StringBuffer sb = new StringBuffer();
+ for (int j = sentStartTok; j <= sentEndTok; j++) {
+ sb.append(tokens[j] + whites[j + 1]);
+ }
+ result[i] = sb.toString();
+ sentStartTok = sentEndTok + 1;
+ }
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ipeirotis/readability/engine/Syllabify.java b/core/src/main/java/com/ipeirotis/readability/engine/Syllabify.java
new file mode 100644
index 0000000..0cb89b8
--- /dev/null
+++ b/core/src/main/java/com/ipeirotis/readability/engine/Syllabify.java
@@ -0,0 +1,73 @@
+package com.ipeirotis.readability.engine;
+
+/*
+ * Created on Jun 5, 2007
+ *
+ */
+
+/**
+ * @author Panos Ipeirotis
+ *
+ * Java Code to estimate the number of syllables in a word.
+ *
+ * Translation of the Perl code by Greg Fast, found at:
+ * http://search.cpan.org/author/GREGFAST/Lingua-EN-Syllable-0.251/
+ *
+ * For documentation and comments
+ * http://search.cpan.org/src/GREGFAST/Lingua
+ * -EN-Syllable-0.251/Syllable.pm
+ *
+ */
+public class Syllabify {
+
+ static String[] SubSyl = { "cial", "tia", "cius", "cious", "giu", "ion", "iou", "sia$", ".ely$" };
+
+ static String[] AddSyl = { "ia", "riet", "dien", "iu", "io", "ii", "[aeiouym]bl$", "[aeiou]{3}", "^mc", "ism$",
+ "[^aeiouy][^aeiouy]l$", "[^l]lien", "^coa[dglx].", "[^gq]ua[^auieo]", "dnt$" };
+
+ public static int syllable(String word) {
+
+ word = word.toLowerCase();
+ word = word.replaceAll("'", " ");
+
+ if (word.equals("i"))
+ return 1;
+ if (word.equals("a"))
+ return 1;
+
+ if (word.endsWith("e")) {
+ word = word.substring(0, word.length() - 1);
+ }
+
+ String[] phonems = word.split("[^aeiouy]+");
+
+ int syl = 0;
+ for (int i = 0; i < SubSyl.length; i++) {
+ String syllabe = SubSyl[i];
+ if (word.matches(syllabe)) {
+ syl--;
+ }
+ }
+ for (int i = 0; i < AddSyl.length; i++) {
+ String syllabe = AddSyl[i];
+ if (word.matches(syllabe)) {
+ syl++;
+ }
+ }
+ if (word.length() == 1) {
+ syl++;
+ }
+
+ for (int i = 0; i < phonems.length; i++) {
+ if (phonems[i].length() > 0)
+ syl++;
+ }
+
+ if (syl == 0) {
+ syl = 1;
+ }
+
+ return syl;
+ }
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/apache/sling/cms/core/insights/impl/BaseInsightProvider.java b/core/src/main/java/org/apache/sling/cms/core/insights/impl/BaseInsightProvider.java
new file mode 100644
index 0000000..c8fd6d5
--- /dev/null
+++ b/core/src/main/java/org/apache/sling/cms/core/insights/impl/BaseInsightProvider.java
@@ -0,0 +1,63 @@
+/*
+ * 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.cms.core.insights.impl;
+
+import org.apache.sling.cms.insights.Insight;
+import org.apache.sling.cms.insights.InsightProvider;
+import org.apache.sling.cms.insights.InsightRequest;
+import org.apache.sling.cms.insights.Message;
+import org.apache.sling.cms.insights.Message.STYLE;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Simple base for the Insight Providers
+ */
+public abstract class BaseInsightProvider implements InsightProvider {
+
+ private static final Logger log = LoggerFactory.getLogger(BaseInsightProvider.class);
+
+ /**
+ * Method for the extending classes to implement, this can safely throw
+ * exceptions and this will trigger a failure result to be returned.
+ *
+ * @param request the request to evaluate
+ * @return the result of evaluation
+ * @throws Exception any exception
+ */
+ protected abstract Insight doEvaluateRequest(InsightRequest request) throws Exception;
+
+ @Override
+ public Insight evaluateRequest(InsightRequest request) {
+ log.trace("evaluatePage");
+ Insight insight = null;
+ try {
+ insight = this.doEvaluateRequest(request);
+ } catch (Exception e) {
+ log.error("Unable to perform check " + getTitle() + " for request " + request, e);
+ insight = new Insight(this, request);
+ insight.getScoreDetails().add(new Message(
+ "Unable to perform check " + getTitle() + " due to unexpected exception", STYLE.DANGER));
+ insight.setSucceeded(false);
+ insight.setScored(false);
+
+ }
+ return insight;
+ }
+}
diff --git a/core/src/main/java/org/apache/sling/cms/core/insights/impl/FakeHttpSession.java b/core/src/main/java/org/apache/sling/cms/core/insights/impl/FakeHttpSession.java
new file mode 100644
index 0000000..ec7a192
--- /dev/null
+++ b/core/src/main/java/org/apache/sling/cms/core/insights/impl/FakeHttpSession.java
@@ -0,0 +1,101 @@
+/*
+ * 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.cms.core.insights.impl;
+
+import java.util.Enumeration;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionContext;
+
+/**
+ * A fake session to use for making server-side requests.
+ */
+@SuppressWarnings("deprecation")
+public class FakeHttpSession implements HttpSession {
+
+ public long getCreationTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getId() {
+ throw new UnsupportedOperationException();
+ }
+
+ public long getLastAccessedTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ public ServletContext getServletContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setMaxInactiveInterval(int i) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getMaxInactiveInterval() {
+ throw new UnsupportedOperationException();
+ }
+
+ public HttpSessionContext getSessionContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object getAttribute(String s) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object getValue(String s) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Enumeration<?> getAttributeNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String[] getValueNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void setAttribute(String s, Object o) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void putValue(String s, Object o) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void removeAttribute(String s) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void removeValue(String s) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void invalidate() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isNew() {
+ throw new UnsupportedOperationException();
+ }
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/apache/sling/cms/core/insights/impl/FakeRequest.java b/core/src/main/java/org/apache/sling/cms/core/insights/impl/FakeRequest.java
new file mode 100644
index 0000000..32c3a4c
--- /dev/null
+++ b/core/src/main/java/org/apache/sling/cms/core/insights/impl/FakeRequest.java
@@ -0,0 +1,298 @@
+/*
+ * 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.cms.core.insights.impl;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+/**
+ * Simple class for faking a HttpServletRequest
+ */
+public class FakeRequest implements HttpServletRequest {
+
+ private final Map<String,Object> attributes;
+
+ private final String method;
+
+ private final Map<String,Object> parameters;
+
+ private final String path;
+
+ private final HttpSession session;
+
+ public FakeRequest(String method, String path) {
+ this.method = method;
+ this.path = path;
+ attributes = new HashMap<>();
+ parameters = new HashMap<>();
+ session = new FakeHttpSession();
+ }
+
+ public FakeRequest(String method, String path, Map<String,Object> params) {
+ this.method = method;
+ this.path = path;
+ attributes = new HashMap<>();
+ parameters = new HashMap<>();
+ session = new FakeHttpSession();
+ for (Iterator<String> iterator = params.keySet().iterator(); iterator.hasNext();) {
+ String key = iterator.next();
+ Object value = params.get(key);
+ if (params.get(key) instanceof String[])
+ parameters.put(key, (String[]) (String[]) value);
+ else
+ parameters.put(key, new String[] { value.toString() });
+ }
+
+ }
+
+ public Object getAttribute(String name) {
+ return attributes.get(name);
+ }
+
+ public Enumeration<?> getAttributeNames() {
+ return Collections.enumeration(attributes.keySet());
+ }
+
+ public String getAuthType() {
+ return null;
+ }
+
+ public String getCharacterEncoding() {
+ return "utf-8";
+ }
+
+ public int getContentLength() {
+ return 0;
+ }
+
+ public String getContentType() {
+ return null;
+ }
+
+ public String getContextPath() {
+ return "";
+ }
+
+ public Cookie[] getCookies() {
+ return new Cookie[0];
+ }
+
+ public long getDateHeader(String name) {
+ return -1L;
+ }
+
+ public String getHeader(String name) {
+ return null;
+ }
+
+ public Enumeration<?> getHeaderNames() {
+ return null;
+ }
+
+ public Enumeration<?> getHeaders(String name) {
+ return null;
+ }
+
+ public ServletInputStream getInputStream() throws IOException {
+ return null;
+ }
+
+ public int getIntHeader(String name) {
+ return -1;
+ }
+
+ public String getLocalAddr() {
+ return null;
+ }
+
+ public Locale getLocale() {
+ return Locale.getDefault();
+ }
+
+ public Enumeration<?> getLocales() {
+ return Collections.enumeration(Collections.singleton(Locale.getDefault()));
+ }
+
+ public String getLocalName() {
+ return null;
+ }
+
+ public int getLocalPort() {
+ return 0;
+ }
+
+ public String getMethod() {
+ return method;
+ }
+
+ public String getParameter(String name) {
+ Object value;
+ try {
+ value = parameters.get(name);
+ if (value instanceof String[]) {
+ return ((String[]) value)[0];
+ }
+ } catch (ClassCastException e) {
+ return null;
+ }
+ return (String) value;
+ }
+
+ public Map<String,Object> getParameterMap() {
+ return parameters;
+ }
+
+ public Enumeration<?> getParameterNames() {
+ return Collections.enumeration(parameters.keySet());
+ }
+
+ public String[] getParameterValues(String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getPathInfo() {
+ return null;
+ }
+
+ public String getPathTranslated() {
+ return null;
+ }
+
+ public String getProtocol() {
+ return "HTTP/1.1";
+ }
+
+ public String getQueryString() {
+ return null;
+ }
+
+ public BufferedReader getReader() throws IOException {
+ return null;
+ }
+
+ public String getRealPath(String path) {
+ return null;
+ }
+
+ public String getRemoteAddr() {
+ return null;
+ }
+
+ public String getRemoteHost() {
+ return null;
+ }
+
+ public int getRemotePort() {
+ return 0;
+ }
+
+ public String getRemoteUser() {
+ return null;
+ }
+
+ public RequestDispatcher getRequestDispatcher(String path) {
+ return null;
+ }
+
+ public String getRequestedSessionId() {
+ return null;
+ }
+
+ public String getRequestURI() {
+ return path;
+ }
+
+ public StringBuffer getRequestURL() {
+ return new StringBuffer("http://localhost:8080" + path);
+ }
+
+ public String getScheme() {
+ return "http";
+ }
+
+ public String getServerName() {
+ return null;
+ }
+
+ public int getServerPort() {
+ return 0;
+ }
+
+ public String getServletPath() {
+ return path;
+ }
+
+ public HttpSession getSession() {
+ return session;
+ }
+
+ public HttpSession getSession(boolean create) {
+ return session;
+ }
+
+ public Principal getUserPrincipal() {
+ return null;
+ }
+
+ public boolean isRequestedSessionIdFromCookie() {
+ return false;
+ }
+
+ public boolean isRequestedSessionIdFromUrl() {
+ return false;
+ }
+
+ public boolean isRequestedSessionIdFromURL() {
+ return false;
+ }
+
+ public boolean isRequestedSessionIdValid() {
+ return false;
+ }
+
+ public boolean isSecure() {
+ return false;
+ }
+ public boolean isUserInRole(String role) {
+ return false;
+ }
+ public void removeAttribute(String name) {
+ attributes.remove(name);
+ }
+ public void setAttribute(String name, Object o) {
+ attributes.put(name, o);
+ }
+ public void setCharacterEncoding(String s) throws UnsupportedEncodingException {
+ // do nothing
+ }
+}
diff --git a/core/src/main/java/org/apache/sling/cms/core/insights/impl/FakeResponse.java b/core/src/main/java/org/apache/sling/cms/core/insights/impl/FakeResponse.java
new file mode 100644
index 0000000..9de5a02
--- /dev/null
+++ b/core/src/main/java/org/apache/sling/cms/core/insights/impl/FakeResponse.java
@@ -0,0 +1,189 @@
+/*
+ * 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.cms.core.insights.impl;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Locale;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * A fake response for making internal requests
+ */
+public class FakeResponse implements HttpServletResponse {
+
+ private String charset;
+
+ private String contentType;
+
+ private ServletOutputStream outputStream;
+
+ private PrintWriter printWriter;
+
+ private final MessageDigest md;
+
+ public FakeResponse(final OutputStream out) throws NoSuchAlgorithmException {
+
+ md = MessageDigest.getInstance("MD5");
+
+ outputStream = new ServletOutputStream() {
+
+ @Override
+ public void write(int b) throws IOException {
+ out.write(b);
+ md.update((byte) b);
+ }
+
+ @Override
+ public void flush() throws IOException {
+ out.flush();
+ }
+
+ @Override
+ public void close() throws IOException {
+ out.close();
+ }
+ };
+ }
+
+ public void addCookie(Cookie cookie1) {
+ }
+
+ public void addDateHeader(String s, long l) {
+ }
+
+ public void addHeader(String s, String s1) {
+ }
+
+ public void addIntHeader(String s, int i) {
+ }
+
+ public boolean containsHeader(String name) {
+ return false;
+ }
+
+ public String encodeRedirectUrl(String url) {
+ return null;
+ }
+
+ public String encodeRedirectURL(String url) {
+ return null;
+ }
+
+ public String encodeUrl(String url) {
+ return null;
+ }
+
+ public String encodeURL(String url) {
+ return null;
+ }
+
+ public void flushBuffer() throws IOException {
+ }
+
+ public int getBufferSize() {
+ return 0;
+ }
+
+ public String getCharacterEncoding() {
+ return charset;
+ }
+
+ public String getContentType() {
+ return contentType;
+ }
+
+ public Locale getLocale() {
+ return null;
+ }
+
+ public String getMD5() {
+ return new String(md.digest());
+ }
+
+ public ServletOutputStream getOutputStream() throws IOException {
+ return outputStream;
+ }
+
+ public PrintWriter getWriter() throws IOException {
+ if (printWriter == null) {
+ java.io.Writer osWriter = new OutputStreamWriter(getOutputStream(), "UTF-8");
+ printWriter = new PrintWriter(osWriter, true);
+ }
+ return printWriter;
+ }
+
+ public boolean isCommitted() {
+ return false;
+ }
+
+ public void reset() {
+ }
+
+ public void resetBuffer() {
+ }
+
+ public void sendError(int i) throws IOException {
+ }
+
+ public void sendError(int i, String s) throws IOException {
+ }
+
+ public void sendRedirect(String s) throws IOException {
+ }
+
+ public void setBufferSize(int i) {
+ }
+
+ public void setCharacterEncoding(String charset) {
+ this.charset = charset;
+ }
+
+ public void setContentLength(int i) {
+ }
+
+ public void setContentType(String type) {
+ contentType = type;
+ }
+
+ public void setDateHeader(String s, long l) {
+ }
+
+ public void setHeader(String s, String s1) {
+ }
+
+ public void setIntHeader(String s, int i) {
+ }
+
+ public void setLocale(Locale locale) {
+ }
+
+ public void setStatus(int i) {
+ }
+
+ public void setStatus(int i, String s) {
+ }
+}
diff --git a/core/src/main/java/org/apache/sling/cms/core/insights/impl/FileInsightRequestImpl.java b/core/src/main/java/org/apache/sling/cms/core/insights/impl/FileInsightRequestImpl.java
new file mode 100644
index 0000000..ce3bd85
--- /dev/null
+++ b/core/src/main/java/org/apache/sling/cms/core/insights/impl/FileInsightRequestImpl.java
@@ -0,0 +1,46 @@
+/*
+ * 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.cms.core.insights.impl;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.cms.File;
+import org.apache.sling.cms.insights.FileInsightRequest;
+
+/**
+ * Implementation of the FileInsightRequest interface
+ */
+public class FileInsightRequestImpl implements FileInsightRequest {
+
+ private File file;
+
+ public FileInsightRequestImpl(File file) {
+ this.file = file;
+ }
+
+ @Override
+ public Resource getResource() {
+ return file.getResource();
+ }
+
+ @Override
+ public File getFile() {
+ return file;
+ }
+
+}
diff --git a/core/src/main/java/org/apache/sling/cms/core/insights/impl/InsightFactoryImpl.java b/core/src/main/java/org/apache/sling/cms/core/insights/impl/InsightFactoryImpl.java
new file mode 100644
index 0000000..7f63bfc
--- /dev/null
+++ b/core/src/main/java/org/apache/sling/cms/core/insights/impl/InsightFactoryImpl.java
@@ -0,0 +1,98 @@
+/*
+ * 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.cms.core.insights.impl;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.sling.cms.File;
+import org.apache.sling.cms.Page;
+import org.apache.sling.cms.insights.Insight;
+import org.apache.sling.cms.insights.InsightFactory;
+import org.apache.sling.cms.insights.InsightProvider;
+import org.apache.sling.cms.insights.InsightRequest;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(immediate = true, service = { InsightFactory.class, ServiceListener.class })
+public class InsightFactoryImpl implements InsightFactory, ServiceListener {
+
+ private static final Logger log = LoggerFactory.getLogger(InsightFactoryImpl.class);
+ private static final Map<String, InsightProvider> insightProviders = new HashMap<>();
+
+ @Activate
+ public void activate(ComponentContext context) throws InvalidSyntaxException {
+ log.info("activate");
+ insightProviders.clear();
+ String filter = "(" + Constants.OBJECTCLASS + "=" + InsightProvider.class.getName() + ")";
+ context.getBundleContext().addServiceListener(this, filter);
+ @SuppressWarnings("unchecked")
+ ServiceReference<InsightProvider>[] serviceReferences = (ServiceReference<InsightProvider>[]) context
+ .getBundleContext().getServiceReferences(InsightProvider.class.getName(), null);
+ if (serviceReferences != null) {
+ Stream.of(serviceReferences).map(sr -> context.getBundleContext().getService(sr))
+ .forEach(provider -> insightProviders.put(provider.getId(), provider));
+ }
+ log.info("Check Service Listener registered successfully!");
+ }
+
+ @Override
+ public void serviceChanged(ServiceEvent event) {
+ @SuppressWarnings("unchecked")
+ ServiceReference<InsightProvider> reference = (ServiceReference<InsightProvider>) event.getServiceReference();
+ InsightProvider provider = (InsightProvider) event.getServiceReference().getBundle().getBundleContext()
+ .getService(reference);
+ synchronized (this) {
+ log.info("Unregistering {}", provider.getId());
+ insightProviders.remove(provider.getId());
+ if (event.getType() == ServiceEvent.MODIFIED || event.getType() == ServiceEvent.REGISTERED) {
+ log.info("Registering {}", provider.getId());
+ insightProviders.put(provider.getId(), provider);
+ }
+ }
+ }
+
+ @Override
+ public Collection<Insight> getInsights(File file) {
+ return getInsights(new FileInsightRequestImpl(file));
+ }
+
+ @Override
+ public Collection<Insight> getInsights(Page page) {
+ return getInsights(new PageInsightRequestImpl(page));
+ }
+
+ private Collection<Insight> getInsights(InsightRequest request) {
+ return insightProviders.values().stream().filter(ip -> ip.isEnabled(request))
+ .map(ip -> ip.evaluateRequest(request)).collect(Collectors.toList());
+
+ }
+
+}
diff --git a/core/src/main/java/org/apache/sling/cms/core/insights/impl/PageInsightRequestImpl.java b/core/src/main/java/org/apache/sling/cms/core/insights/impl/PageInsightRequestImpl.java
new file mode 100644
index 0000000..59ca53b
--- /dev/null
+++ b/core/src/main/java/org/apache/sling/cms/core/insights/impl/PageInsightRequestImpl.java
@@ -0,0 +1,107 @@
+/*
+ * 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.cms.core.insights.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.cms.Page;
+import org.apache.sling.cms.insights.PageInsightRequest;
+import org.apache.sling.engine.SlingRequestProcessor;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of the PageInsightRequest interface
+ */
+public class PageInsightRequestImpl implements PageInsightRequest {
+
+ private static final Logger log = LoggerFactory.getLogger(PageInsightRequestImpl.class);
+
+ private Map<String, String> markupCache = new HashMap<>();
+
+ private final Page page;
+
+ @Inject
+ private SlingRequestProcessor requestProcessor;
+
+ private final ResourceResolver resourceResolver;
+
+ public PageInsightRequestImpl(Page page) {
+ this.page = page;
+ this.resourceResolver = page.getResource().getResourceResolver();
+ }
+
+ private String getContents(String url) {
+ log.trace("getLocalPageHTML");
+ if (!markupCache.containsKey(url)) {
+ String requestPath = page.getPath() + ".html";
+ log.debug("Loading local page HTML from {}", requestPath);
+ HttpServletRequest req = new FakeRequest("GET", requestPath);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ HttpServletResponse resp;
+ try {
+ resp = new FakeResponse(out);
+ requestProcessor.processRequest(req, resp, resourceResolver);
+ } catch (ServletException | IOException | NoSuchAlgorithmException e) {
+ log.warn("Exception retrieving page contents for {}", url, e);
+ }
+ markupCache.put(url, out.toString());
+ }
+ return markupCache.get(url);
+ }
+
+ @Override
+ public Page getPage() {
+ return this.page;
+ }
+
+ @Override
+ public String getPageBodyHtml() throws IOException {
+ return getContents(page.getPath() + "/jcr:content/container.html");
+ }
+
+ @Override
+ public Document getPageDocument() throws IOException {
+ return Jsoup.parse(getPageHtml());
+ }
+
+ @Override
+ public String getPageHtml() throws IOException {
+ return getContents(page.getPath() + ".html");
+ }
+
+ @Override
+ public Resource getResource() {
+ return page.getResource();
+ }
+
+}
diff --git a/core/src/main/java/org/apache/sling/cms/core/insights/impl/ReadabilityInsightProvider.java b/core/src/main/java/org/apache/sling/cms/core/insights/impl/ReadabilityInsightProvider.java
new file mode 100644
index 0000000..ef7662f
--- /dev/null
+++ b/core/src/main/java/org/apache/sling/cms/core/insights/impl/ReadabilityInsightProvider.java
@@ -0,0 +1,5 @@
+package org.apache.sling.cms.core.insights.impl;
+
+public class ReadabilityInsightProvider {
+
+}
diff --git a/core/src/main/java/org/apache/sling/cms/core/internal/models/PageImpl.java b/core/src/main/java/org/apache/sling/cms/core/internal/models/FileImpl.java
similarity index 62%
copy from core/src/main/java/org/apache/sling/cms/core/internal/models/PageImpl.java
copy to core/src/main/java/org/apache/sling/cms/core/internal/models/FileImpl.java
index 1de2819..2e2e21f 100644
--- a/core/src/main/java/org/apache/sling/cms/core/internal/models/PageImpl.java
+++ b/core/src/main/java/org/apache/sling/cms/core/internal/models/FileImpl.java
@@ -16,21 +16,14 @@
*/
package org.apache.sling.cms.core.internal.models;
-import java.util.ArrayList;
import java.util.Calendar;
-import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
-import org.apache.commons.lang.StringUtils;
-import org.apache.jackrabbit.JcrConstants;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
-import org.apache.sling.cms.CMSConstants;
-import org.apache.sling.cms.CMSUtils;
-import org.apache.sling.cms.Page;
-import org.apache.sling.cms.PageTemplate;
+import org.apache.sling.cms.File;
import org.apache.sling.cms.Site;
import org.apache.sling.cms.SiteManager;
import org.apache.sling.models.annotations.Default;
@@ -38,19 +31,10 @@ import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.Optional;
/**
- * A model representing a page.
+ * A model representing a file
*/
-@Model(adaptables = Resource.class, adapters = Page.class)
-public class PageImpl implements Page {
-
- public static final Page getContainingPage(Resource resource) {
- Resource pageRsrc = CMSUtils.findParentResourceofType(resource, CMSConstants.NT_PAGE);
- Page page = null;
- if (pageRsrc != null) {
- page = pageRsrc.adaptTo(Page.class);
- }
- return page;
- }
+@Model(adaptables = Resource.class, adapters = File.class)
+public class FileImpl implements File {
@Inject
@Optional
@@ -58,6 +42,10 @@ public class PageImpl implements Page {
private Resource contentResource;
@Inject
+ @Named("jcr:content/jcr:mimeType")
+ private String contentType;
+
+ @Inject
@Optional
@Named("jcr:content/jcr:created")
private Calendar created;
@@ -85,86 +73,74 @@ public class PageImpl implements Page {
protected Resource resource;
@Inject
- @Optional
- @Named(JcrConstants.JCR_CONTENT + "/" + CMSConstants.PN_TAXONOMY)
- private String[] taxonomy;
-
- @Inject
- @Optional
- @Named("jcr:content/sling:template")
- private String template;
-
- @Inject
- @Named("jcr:content/jcr:title")
- @Optional
- private String title;
-
- @Inject
@Named("jcr:primaryType")
private String type;
- public PageImpl(Resource resource) {
+ public FileImpl(Resource resource) {
this.resource = resource;
}
+ @Override
public Resource getContentResource() {
return contentResource;
}
+ @Override
+ public String getContentType() {
+ return contentType;
+ }
+
+ @Override
public Calendar getCreated() {
return created;
}
+ @Override
public String getCreatedBy() {
return createdBy;
}
- public String[] getKeywords() {
- List<String> keywords = new ArrayList<>();
- if (taxonomy != null) {
- for (String item : taxonomy) {
- Resource resource = this.resource.getResourceResolver().getResource(item);
- if (resource != null) {
- keywords.add(resource.getValueMap().get(CMSConstants.PN_TITLE, String.class));
- }
- }
- }
- return keywords.toArray(new String[keywords.size()]);
- }
-
+ @Override
public Calendar getLastModified() {
return lastModified != null ? lastModified : created;
}
+ @Override
public String getLastModifiedBy() {
return lastModifiedBy != null ? lastModifiedBy : createdBy;
}
+ @Override
public String getName() {
return resource.getName();
}
+ @Override
public Resource getParent() {
return resource.getParent();
}
+ @Override
public String getPath() {
return resource.getPath();
}
+ @Override
public ValueMap getProperties() {
return getContentResource().getValueMap();
}
+ @Override
public String getPublishedPath() {
Site site = getSite();
if (site != null) {
- return resource.getPath().replace(site.getPath(), "") + ".html";
+ return resource.getPath().replace(site.getPath(), "");
} else {
- return resource.getPath() + ".html";
+ return resource.getPath();
}
}
+ @Override
public String getPublishedUrl() {
Site site = getSite();
if (site != null) {
@@ -174,10 +150,12 @@ public class PageImpl implements Page {
}
}
+ @Override
public Resource getResource() {
return resource;
}
+ @Override
public Site getSite() {
SiteManager siteMgr = resource.adaptTo(SiteManager.class);
Site site = null;
@@ -187,27 +165,7 @@ public class PageImpl implements Page {
return site;
}
- public PageTemplate getTemplate() {
- Resource templateResource = this.resource.getResourceResolver().getResource(template);
- if (templateResource != null) {
- return templateResource.adaptTo(PageTemplate.class);
- } else {
- return null;
- }
- }
-
- public String getTemplatePath() {
- return this.template;
- }
-
- public String getTitle() {
- if (StringUtils.isNotEmpty(title)) {
- return title;
- } else {
- return resource.getName();
- }
- }
-
+ @Override
public boolean isPublished() {
return published;
}
diff --git a/core/src/main/java/org/apache/sling/cms/core/internal/models/FileManagerImpl.java b/core/src/main/java/org/apache/sling/cms/core/internal/models/FileManagerImpl.java
new file mode 100644
index 0000000..f4ac120
--- /dev/null
+++ b/core/src/main/java/org/apache/sling/cms/core/internal/models/FileManagerImpl.java
@@ -0,0 +1,47 @@
+/*
+ * 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.cms.core.internal.models;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.cms.CMSConstants;
+import org.apache.sling.cms.CMSUtils;
+import org.apache.sling.cms.File;
+import org.apache.sling.cms.FileManager;
+import org.apache.sling.models.annotations.Model;
+
+/**
+ * A model used to retrieve files.
+ */
+@Model(adaptables = Resource.class, adapters = FileManager.class)
+public class FileManagerImpl implements FileManager {
+
+ private final File file;
+
+ public FileManagerImpl(Resource containingResource) {
+ Resource fileResource = CMSUtils.findParentResourceofType(containingResource, CMSConstants.NT_PAGE);
+ if (fileResource != null) {
+ file = fileResource.adaptTo(File.class);
+ } else {
+ file = null;
+ }
+ }
+
+ @Override
+ public File getFile() {
+ return file;
+ }
+}
diff --git a/core/src/main/java/org/apache/sling/cms/core/internal/models/PageImpl.java b/core/src/main/java/org/apache/sling/cms/core/internal/models/PageImpl.java
index 1de2819..7808f99 100644
--- a/core/src/main/java/org/apache/sling/cms/core/internal/models/PageImpl.java
+++ b/core/src/main/java/org/apache/sling/cms/core/internal/models/PageImpl.java
@@ -123,9 +123,9 @@ public class PageImpl implements Page {
List<String> keywords = new ArrayList<>();
if (taxonomy != null) {
for (String item : taxonomy) {
- Resource resource = this.resource.getResourceResolver().getResource(item);
- if (resource != null) {
- keywords.add(resource.getValueMap().get(CMSConstants.PN_TITLE, String.class));
+ Resource rsrc = this.resource.getResourceResolver().getResource(item);
+ if (rsrc != null) {
+ keywords.add(rsrc.getValueMap().get(CMSConstants.PN_TITLE, String.class));
}
}
}
@@ -178,7 +178,7 @@ public class PageImpl implements Page {
return resource;
}
- public Site getSite() {
+ public Site getSite() {
SiteManager siteMgr = resource.adaptTo(SiteManager.class);
Site site = null;
if (siteMgr != null) {
diff --git a/pom.xml b/pom.xml
index f9e2671..94548b5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -170,6 +170,12 @@
<version>1.6.8</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <artifactId>jsoup</artifactId>
+ <version>1.11.3</version>
+ <groupId>org.jsoup</groupId>
+ <scope>provided</scope>
+ </dependency>
</dependencies>
</dependencyManagement>