├── resources
├── .gitignore
├── solr
│ ├── multicore
│ │ ├── posts
│ │ │ ├── .gitignore
│ │ │ └── conf
│ │ │ │ ├── spellings.txt
│ │ │ │ ├── protwords.txt
│ │ │ │ ├── synonyms.txt
│ │ │ │ ├── stopwords.txt
│ │ │ │ └── solrconfig.xml
│ │ ├── channels
│ │ │ ├── .gitignore
│ │ │ └── conf
│ │ │ │ ├── spellings.txt
│ │ │ │ ├── protwords.txt
│ │ │ │ ├── synonyms.txt
│ │ │ │ ├── stopwords.txt
│ │ │ │ ├── solrconfig.xml
│ │ │ │ └── schema.xml
│ │ └── solr.xml
│ └── start.jar
├── schema
│ ├── update-schema-0.sql
│ ├── drop-schema.sql
│ └── create-schema.sql
└── init_d
│ ├── buddycloud-solr
│ ├── buddycloud-crawler
│ └── buddycloud-search
├── .gitignore
├── design docs
├── Architecture.png
├── FindChannels.png
└── DiscoverChannels.png
├── .m2
└── org
│ └── igniterealtime
│ └── whack
│ ├── 1.0.0
│ ├── whack-1.0.0.jar
│ └── whack-1.0.0.pom
│ └── maven-metadata-local.xml
├── src
├── main
│ └── java
│ │ ├── org
│ │ └── jivesoftware
│ │ │ └── smackx
│ │ │ └── pubsub
│ │ │ ├── BuddycloudFirehoseNode.java
│ │ │ ├── BuddycloudAffiliationsProvider.java
│ │ │ ├── BuddycloudAffiliationProvider.java
│ │ │ ├── BuddycloudAffiliations.java
│ │ │ ├── BuddycloudAffiliation.java
│ │ │ ├── BuddycloudPubsubManager.java
│ │ │ └── BuddycloudNode.java
│ │ └── com
│ │ └── buddycloud
│ │ └── channeldirectory
│ │ ├── cli
│ │ ├── Query.java
│ │ ├── QueryToDBMS.java
│ │ ├── QueryToSolr.java
│ │ └── Main.java
│ │ ├── search
│ │ ├── handler
│ │ │ ├── QueryHandler.java
│ │ │ ├── response
│ │ │ │ ├── ContentData.java
│ │ │ │ ├── Geolocation.java
│ │ │ │ ├── FakeDataGenerator.java
│ │ │ │ ├── ChannelData.java
│ │ │ │ └── PostData.java
│ │ │ ├── AbstractQueryHandler.java
│ │ │ ├── common
│ │ │ │ ├── mahout
│ │ │ │ │ ├── RecommendationResponse.java
│ │ │ │ │ ├── ChannelRecommenderDataModel.java
│ │ │ │ │ ├── MemoryRecommenderDataModel.java
│ │ │ │ │ ├── PostgreSQLRecommenderDataModel.java
│ │ │ │ │ └── ChannelRecommender.java
│ │ │ │ └── PostQueryHandler.java
│ │ │ ├── recommendation
│ │ │ │ └── RecommendationQueryHandler.java
│ │ │ ├── similarity
│ │ │ │ └── SimilarityQueryHandler.java
│ │ │ ├── metadata
│ │ │ │ └── MetadataQueryHandler.java
│ │ │ ├── active
│ │ │ │ └── MostActiveQueryHandler.java
│ │ │ ├── nearby
│ │ │ │ └── NearbyQueryHandler.java
│ │ │ └── content
│ │ │ │ └── ContentQueryHandler.java
│ │ ├── utils
│ │ │ ├── GeolocationUtils.java
│ │ │ ├── FeatureUtils.java
│ │ │ └── XMPPUtils.java
│ │ ├── rsm
│ │ │ ├── RSM.java
│ │ │ ├── SolrRSMUtils.java
│ │ │ ├── MahoutRSMUtils.java
│ │ │ └── RSMUtils.java
│ │ ├── Main.java
│ │ └── ChannelDirectoryComponent.java
│ │ ├── commons
│ │ ├── solr
│ │ │ ├── SolrUtils.java
│ │ │ └── SolrServerFactory.java
│ │ ├── ConfigurationUtils.java
│ │ └── db
│ │ │ ├── CreateSchema.java
│ │ │ └── ChannelDirectoryDataSource.java
│ │ └── crawler
│ │ ├── node
│ │ ├── NodeCrawler.java
│ │ ├── DiscoveryUtils.java
│ │ └── FirehoseCrawler.java
│ │ ├── PubSubManagers.java
│ │ ├── Main.java
│ │ └── PubSubSubscriptionListener.java
├── log4j.properties
└── test
│ └── java
│ └── com
│ └── buddycloud
│ ├── HSQLDBTest.java
│ └── channeldirectory
│ └── rsm
│ └── RSMTest.java
├── queries.json
├── configuration.properties.example
├── bin
├── exec-query
├── stop-solr.sh
├── setup-schema.sh
├── stop-crawler.sh
├── start-solr.sh
├── stop-search.sh
├── start-search.sh
├── start-crawler.sh
├── start-solr.bat
├── start-crawler.bat
├── start-search.bat
└── setup-schema.bat
└── pom.xml
/resources/.gitignore:
--------------------------------------------------------------------------------
1 | /channel-taste
2 |
--------------------------------------------------------------------------------
/resources/solr/multicore/posts/.gitignore:
--------------------------------------------------------------------------------
1 | /data
2 |
--------------------------------------------------------------------------------
/resources/solr/multicore/channels/.gitignore:
--------------------------------------------------------------------------------
1 | /data
2 |
--------------------------------------------------------------------------------
/resources/solr/multicore/posts/conf/spellings.txt:
--------------------------------------------------------------------------------
1 | pizza
2 | history
3 |
--------------------------------------------------------------------------------
/resources/solr/multicore/channels/conf/spellings.txt:
--------------------------------------------------------------------------------
1 | pizza
2 | history
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | .settings
3 | .project
4 | .classpath
5 | configuration.properties
6 |
--------------------------------------------------------------------------------
/resources/schema/update-schema-0.sql:
--------------------------------------------------------------------------------
1 | ALTER TABLE subscribed_node ADD last_item_crawled VARCHAR(300);
--------------------------------------------------------------------------------
/resources/solr/start.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/buddycloud/channel-directory/HEAD/resources/solr/start.jar
--------------------------------------------------------------------------------
/design docs/Architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/buddycloud/channel-directory/HEAD/design docs/Architecture.png
--------------------------------------------------------------------------------
/design docs/FindChannels.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/buddycloud/channel-directory/HEAD/design docs/FindChannels.png
--------------------------------------------------------------------------------
/design docs/DiscoverChannels.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/buddycloud/channel-directory/HEAD/design docs/DiscoverChannels.png
--------------------------------------------------------------------------------
/.m2/org/igniterealtime/whack/1.0.0/whack-1.0.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/buddycloud/channel-directory/HEAD/.m2/org/igniterealtime/whack/1.0.0/whack-1.0.0.jar
--------------------------------------------------------------------------------
/src/main/java/org/jivesoftware/smackx/pubsub/BuddycloudFirehoseNode.java:
--------------------------------------------------------------------------------
1 | package org.jivesoftware.smackx.pubsub;
2 |
3 | import org.jivesoftware.smack.XMPPConnection;
4 |
5 | public class BuddycloudFirehoseNode extends Node {
6 |
7 | public BuddycloudFirehoseNode(XMPPConnection connection) {
8 | super(connection, "/firehose");
9 | }
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/queries.json:
--------------------------------------------------------------------------------
1 | [
2 | {name="personal-channels-count", type="solr", agg="count", core="channels", q="channel-type:personal"},
3 | {name="topic-channels-count", type="solr", agg="count", core="channels", q="channel-type:topic"},
4 | {name="post-count", type="solr", agg="count", core="posts", q="content:[* TO *]"},
5 | {name="domain-count", type="dbms", q="SELECT COUNT(*) FROM subscribed_server"}
6 | ]
--------------------------------------------------------------------------------
/.m2/org/igniterealtime/whack/maven-metadata-local.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | org.igniterealtime
4 | whack
5 |
6 | 1.0.0
7 |
8 | 1.0.0
9 |
10 | 20140613143036
11 |
12 |
13 |
--------------------------------------------------------------------------------
/resources/schema/drop-schema.sql:
--------------------------------------------------------------------------------
1 | DROP TABLE IF EXISTS subscribed_server;
2 | DROP TABLE IF EXISTS subscribed_node;
3 | DROP TABLE IF EXISTS taste_preferences;
4 | DROP TABLE IF EXISTS item;
5 | DROP TABLE IF EXISTS t_user;
6 | DROP TABLE IF EXISTS taste_item_similarity;
7 | DROP TABLE IF EXISTS channel_activity;
8 |
9 | DROP SEQUENCE IF EXISTS item_id_seq;
10 | DROP SEQUENCE IF EXISTS user_id_seq;
11 |
--------------------------------------------------------------------------------
/.m2/org/igniterealtime/whack/1.0.0/whack-1.0.0.pom:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | org.igniterealtime
6 | whack
7 | 1.0.0
8 | POM was created from install:install-file
9 |
10 |
--------------------------------------------------------------------------------
/src/main/java/org/jivesoftware/smackx/pubsub/BuddycloudAffiliationsProvider.java:
--------------------------------------------------------------------------------
1 | package org.jivesoftware.smackx.pubsub;
2 |
3 | import java.util.List;
4 | import java.util.Map;
5 |
6 | import org.jivesoftware.smack.packet.PacketExtension;
7 | import org.jivesoftware.smack.provider.EmbeddedExtensionProvider;
8 |
9 | public class BuddycloudAffiliationsProvider extends EmbeddedExtensionProvider {
10 |
11 | @SuppressWarnings("unchecked")
12 | @Override
13 | protected PacketExtension createReturnExtension(String currentElement,
14 | String currentNamespace, Map attributeMap,
15 | List extends PacketExtension> content) {
16 | return new BuddycloudAffiliations((List)content);
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/org/jivesoftware/smackx/pubsub/BuddycloudAffiliationProvider.java:
--------------------------------------------------------------------------------
1 | package org.jivesoftware.smackx.pubsub;
2 |
3 | import java.util.List;
4 | import java.util.Map;
5 |
6 | import org.jivesoftware.smack.packet.PacketExtension;
7 | import org.jivesoftware.smack.provider.EmbeddedExtensionProvider;
8 |
9 | public class BuddycloudAffiliationProvider extends EmbeddedExtensionProvider {
10 |
11 | @Override
12 | protected PacketExtension createReturnExtension(String currentElement,
13 | String currentNamespace, Map attributeMap,
14 | List extends PacketExtension> content) {
15 | return new BuddycloudAffiliation(attributeMap.get("jid"),
16 | BuddycloudAffiliation.Type.valueOf(attributeMap.get("affiliation")));
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/configuration.properties.example:
--------------------------------------------------------------------------------
1 | # Search engine properties
2 |
3 | xmpp.host=localhost
4 | xmpp.port=5275
5 | xmpp.subdomain=channeldirectory
6 | xmpp.secretkey=secret
7 |
8 | # Crawler properties
9 |
10 | crawler.xmpp.username=crawler-user
11 | crawler.xmpp.password=crawler-pass
12 | crawler.xmpp.host=hostname.buddycloud.com
13 | crawler.xmpp.servicename=buddycloud.com
14 | crawler.xmpp.port=5222
15 | crawler.servertocrawl=broadcaster.buddycloud.com
16 |
17 | # In milliseconds
18 | crawler.crawlinterval=300000
19 |
20 | # Solr cores
21 |
22 | solr.channelcore=http://localhost:8983/solr/channels/
23 | solr.postcore=http://localhost:8983/solr/posts/
24 |
25 | # Recommender: [memory, postgresql]
26 |
27 | mahout.recommender=postgresql
28 | mahout.jdbc.url=jdbc:postgresql://localhost:5432/channeldir?user=postgres&password=postgres
29 | mahout.dumpfile=resources/channel-taste/dump.csv
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/cli/Query.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.cli;
17 |
18 | import java.util.Properties;
19 |
20 | /**
21 | * @author Abmar
22 | *
23 | */
24 | public interface Query {
25 |
26 | public String exec(String args, Properties configuration) throws Exception;
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/resources/solr/multicore/channels/conf/protwords.txt:
--------------------------------------------------------------------------------
1 | # The ASF licenses this file to You under the Apache License, Version 2.0
2 | # (the "License"); you may not use this file except in compliance with
3 | # the License. You may obtain a copy of the License at
4 | #
5 | # http://www.apache.org/licenses/LICENSE-2.0
6 | #
7 | # Unless required by applicable law or agreed to in writing, software
8 | # distributed under the License is distributed on an "AS IS" BASIS,
9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | # See the License for the specific language governing permissions and
11 | # limitations under the License.
12 |
13 | #-----------------------------------------------------------------------
14 | # Use a protected word file to protect against the stemmer reducing two
15 | # unrelated words to the same base word.
16 |
17 | # Some non-words that normally won't be encountered,
18 | # just to test that they won't be stemmed.
19 | dontstems
20 | zwhacky
21 |
22 |
--------------------------------------------------------------------------------
/resources/solr/multicore/posts/conf/protwords.txt:
--------------------------------------------------------------------------------
1 | # The ASF licenses this file to You under the Apache License, Version 2.0
2 | # (the "License"); you may not use this file except in compliance with
3 | # the License. You may obtain a copy of the License at
4 | #
5 | # http://www.apache.org/licenses/LICENSE-2.0
6 | #
7 | # Unless required by applicable law or agreed to in writing, software
8 | # distributed under the License is distributed on an "AS IS" BASIS,
9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | # See the License for the specific language governing permissions and
11 | # limitations under the License.
12 |
13 | #-----------------------------------------------------------------------
14 | # Use a protected word file to protect against the stemmer reducing two
15 | # unrelated words to the same base word.
16 |
17 | # Some non-words that normally won't be encountered,
18 | # just to test that they won't be stemmed.
19 | dontstems
20 | zwhacky
21 |
22 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/handler/QueryHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.handler;
17 |
18 | import org.xmpp.packet.IQ;
19 |
20 | /**
21 | * Handle content queries (iq gets) to this component.
22 | *
23 | */
24 | public interface QueryHandler {
25 |
26 | IQ handle(IQ query);
27 |
28 | String getNamespace();
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/bin/exec-query:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Licensed to the Apache Software Foundation (ASF) under one or more
4 | # contributor license agreements. See the NOTICE file distributed with
5 | # this work for additional information regarding copyright ownership.
6 | # The ASF licenses this file to You under the Apache License, Version 2.0
7 | # (the "License"); you may not use this file except in compliance with
8 | # the License. You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 |
18 | # -----------------------------------------------------------------------------
19 | # Execute a query directly into buddycloud channel directory
20 | # -----------------------------------------------------------------------------
21 |
22 | # Cd to Search home and performs the query
23 |
24 | BIN_DIR=`dirname $0`
25 | cd "$BIN_DIR"/..
26 |
27 | java -cp .:./*:./lib/* com.buddycloud.channeldirectory.cli.Main "$@"
--------------------------------------------------------------------------------
/bin/stop-solr.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Licensed to the Apache Software Foundation (ASF) under one or more
4 | # contributor license agreements. See the NOTICE file distributed with
5 | # this work for additional information regarding copyright ownership.
6 | # The ASF licenses this file to You under the Apache License, Version 2.0
7 | # (the "License"); you may not use this file except in compliance with
8 | # the License. You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 |
18 | # -----------------------------------------------------------------------------
19 | # Stop script for the solr server
20 | # -----------------------------------------------------------------------------
21 |
22 | BIN_DIR=`dirname $0`
23 | SOLR_PID=solr.pid
24 | cd "$BIN_DIR"
25 |
26 | if [ ! -f $SOLR_PID ]; then
27 | echo PID file does not exist
28 | exit 1
29 | fi
30 |
31 | kill `cat $SOLR_PID`
32 | rm $SOLR_PID
33 | exit 0
34 |
--------------------------------------------------------------------------------
/resources/solr/multicore/posts/conf/synonyms.txt:
--------------------------------------------------------------------------------
1 | # The ASF licenses this file to You under the Apache License, Version 2.0
2 | # (the "License"); you may not use this file except in compliance with
3 | # the License. You may obtain a copy of the License at
4 | #
5 | # http://www.apache.org/licenses/LICENSE-2.0
6 | #
7 | # Unless required by applicable law or agreed to in writing, software
8 | # distributed under the License is distributed on an "AS IS" BASIS,
9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | # See the License for the specific language governing permissions and
11 | # limitations under the License.
12 |
13 | #-----------------------------------------------------------------------
14 | #some test synonym mappings unlikely to appear in real input text
15 | aaafoo => aaabar
16 | bbbfoo => bbbfoo bbbbar
17 | cccfoo => cccbar cccbaz
18 | fooaaa,baraaa,bazaaa
19 |
20 | # Some synonym groups specific to this example
21 | GB,gib,gigabyte,gigabytes
22 | MB,mib,megabyte,megabytes
23 | Television, Televisions, TV, TVs
24 | #notice we use "gib" instead of "GiB" so any WordDelimiterFilter coming
25 | #after us won't split it into two words.
26 |
27 | # Synonym mappings can be used for spelling correction too
28 | pixima => pixma
29 |
30 |
--------------------------------------------------------------------------------
/bin/setup-schema.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Licensed to the Apache Software Foundation (ASF) under one or more
4 | # contributor license agreements. See the NOTICE file distributed with
5 | # this work for additional information regarding copyright ownership.
6 | # The ASF licenses this file to You under the Apache License, Version 2.0
7 | # (the "License"); you may not use this file except in compliance with
8 | # the License. You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 |
18 | # -----------------------------------------------------------------------------
19 | # Start script for the Channel Directory Solr
20 | # -----------------------------------------------------------------------------
21 |
22 | # Go to ChannelDir home and invoke the CreateSchema class
23 |
24 | BIN_DIR=`dirname $0`
25 | cd "$BIN_DIR"/..
26 | java -cp .:./*:./lib/* com.buddycloud.channeldirectory.commons.db.CreateSchema
27 |
28 | exit 0
29 |
--------------------------------------------------------------------------------
/resources/solr/multicore/channels/conf/synonyms.txt:
--------------------------------------------------------------------------------
1 | # The ASF licenses this file to You under the Apache License, Version 2.0
2 | # (the "License"); you may not use this file except in compliance with
3 | # the License. You may obtain a copy of the License at
4 | #
5 | # http://www.apache.org/licenses/LICENSE-2.0
6 | #
7 | # Unless required by applicable law or agreed to in writing, software
8 | # distributed under the License is distributed on an "AS IS" BASIS,
9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | # See the License for the specific language governing permissions and
11 | # limitations under the License.
12 |
13 | #-----------------------------------------------------------------------
14 | #some test synonym mappings unlikely to appear in real input text
15 | aaafoo => aaabar
16 | bbbfoo => bbbfoo bbbbar
17 | cccfoo => cccbar cccbaz
18 | fooaaa,baraaa,bazaaa
19 |
20 | # Some synonym groups specific to this example
21 | GB,gib,gigabyte,gigabytes
22 | MB,mib,megabyte,megabytes
23 | Television, Televisions, TV, TVs
24 | #notice we use "gib" instead of "GiB" so any WordDelimiterFilter coming
25 | #after us won't split it into two words.
26 |
27 | # Synonym mappings can be used for spelling correction too
28 | pixima => pixma
29 |
30 |
--------------------------------------------------------------------------------
/bin/stop-crawler.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Licensed to the Apache Software Foundation (ASF) under one or more
4 | # contributor license agreements. See the NOTICE file distributed with
5 | # this work for additional information regarding copyright ownership.
6 | # The ASF licenses this file to You under the Apache License, Version 2.0
7 | # (the "License"); you may not use this file except in compliance with
8 | # the License. You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 |
18 | # -----------------------------------------------------------------------------
19 | # Stop script for the crawler
20 | # -----------------------------------------------------------------------------
21 |
22 | BIN_DIR=`dirname $0`
23 | CRAWLER_PID=crawler.pid
24 | cd "$BIN_DIR"
25 |
26 | if [ ! -f $CRAWLER_PID ]; then
27 | echo PID file does not exist
28 | exit 1
29 | fi
30 |
31 | kill `cat $CRAWLER_PID`
32 | rm $CRAWLER_PID
33 | exit 0
34 |
--------------------------------------------------------------------------------
/bin/start-solr.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Licensed to the Apache Software Foundation (ASF) under one or more
4 | # contributor license agreements. See the NOTICE file distributed with
5 | # this work for additional information regarding copyright ownership.
6 | # The ASF licenses this file to You under the Apache License, Version 2.0
7 | # (the "License"); you may not use this file except in compliance with
8 | # the License. You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 |
18 | # -----------------------------------------------------------------------------
19 | # Start script for the Channel Directory Solr
20 | # -----------------------------------------------------------------------------
21 |
22 | # Go to Solr home and start it
23 |
24 | BIN_DIR=`dirname $0`
25 | BIN_DIR=`cd $BIN_DIR && pwd`
26 | cd "$BIN_DIR"/../resources/solr
27 | java -Dsolr.solr.home=multicore -jar start.jar &
28 | echo $! > "$BIN_DIR"/solr.pid
29 | exit 0
30 |
--------------------------------------------------------------------------------
/bin/stop-search.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Licensed to the Apache Software Foundation (ASF) under one or more
4 | # contributor license agreements. See the NOTICE file distributed with
5 | # this work for additional information regarding copyright ownership.
6 | # The ASF licenses this file to You under the Apache License, Version 2.0
7 | # (the "License"); you may not use this file except in compliance with
8 | # the License. You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 |
18 | # -----------------------------------------------------------------------------
19 | # Stop script for the Channel Directory search engine
20 | # -----------------------------------------------------------------------------
21 |
22 | BIN_DIR=`dirname $0`
23 | SEARCH_PID=search.pid
24 | cd "$BIN_DIR"
25 |
26 | if [ ! -f $SEARCH_PID ]; then
27 | echo PID file does not exist
28 | exit 1
29 | fi
30 |
31 | kill `cat $SEARCH_PID`
32 | rm $SEARCH_PID
33 | exit 0
34 |
--------------------------------------------------------------------------------
/bin/start-search.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Licensed to the Apache Software Foundation (ASF) under one or more
4 | # contributor license agreements. See the NOTICE file distributed with
5 | # this work for additional information regarding copyright ownership.
6 | # The ASF licenses this file to You under the Apache License, Version 2.0
7 | # (the "License"); you may not use this file except in compliance with
8 | # the License. You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 |
18 | # -----------------------------------------------------------------------------
19 | # Start script for the Channel Directory search engine
20 | # -----------------------------------------------------------------------------
21 |
22 | # Go to Search home and start it
23 |
24 | BIN_DIR=`dirname $0`
25 | BIN_DIR=`cd $BIN_DIR && pwd`
26 | cd "$BIN_DIR"/..
27 | java -cp .:./*:./lib/* com.buddycloud.channeldirectory.search.Main &
28 | echo $! > "$BIN_DIR"/search.pid
29 | exit 0
30 |
--------------------------------------------------------------------------------
/src/main/java/org/jivesoftware/smackx/pubsub/BuddycloudAffiliations.java:
--------------------------------------------------------------------------------
1 | package org.jivesoftware.smackx.pubsub;
2 |
3 | import java.util.Collections;
4 | import java.util.List;
5 |
6 | import org.jivesoftware.smack.packet.PacketExtension;
7 | import org.jivesoftware.smack.util.XmlStringBuilder;
8 | import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
9 |
10 | public class BuddycloudAffiliations implements PacketExtension {
11 |
12 | public static final String ELEMENT_NAME = "affiliations";
13 |
14 | protected List items = Collections.emptyList();
15 |
16 | public BuddycloudAffiliations(List subList) {
17 | items = subList;
18 | }
19 |
20 | public List getAffiliations() {
21 | return items;
22 | }
23 |
24 | public String getElementName() {
25 | return ELEMENT_NAME;
26 | }
27 |
28 | public String getNamespace() {
29 | return PubSubNamespace.OWNER.getXmlns();
30 | }
31 |
32 | @Override
33 | public CharSequence toXML() {
34 | XmlStringBuilder xml = new XmlStringBuilder();
35 | xml.openElement(getElementName());
36 | if (items != null) {
37 | for (BuddycloudAffiliation affiliation : items) {
38 | xml.append(affiliation.toXML());
39 | }
40 | }
41 | xml.closeElement(getElementName());
42 | return xml;
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/bin/start-crawler.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Licensed to the Apache Software Foundation (ASF) under one or more
4 | # contributor license agreements. See the NOTICE file distributed with
5 | # this work for additional information regarding copyright ownership.
6 | # The ASF licenses this file to You under the Apache License, Version 2.0
7 | # (the "License"); you may not use this file except in compliance with
8 | # the License. You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 |
18 | # -----------------------------------------------------------------------------
19 | # Start script for the Channel Directory Crawler
20 | # -----------------------------------------------------------------------------
21 |
22 | # Go to Search home and start the Crawler
23 |
24 | BIN_DIR=`dirname $0`
25 | BIN_DIR=`cd $BIN_DIR && pwd`
26 | cd "$BIN_DIR"/..
27 | java -cp .:./*:./lib/* com.buddycloud.channeldirectory.crawler.Main &
28 | echo $! > "$BIN_DIR"/crawler.pid
29 | exit 0
30 |
--------------------------------------------------------------------------------
/src/main/java/org/jivesoftware/smackx/pubsub/BuddycloudAffiliation.java:
--------------------------------------------------------------------------------
1 | package org.jivesoftware.smackx.pubsub;
2 |
3 | import org.jivesoftware.smack.packet.PacketExtension;
4 | import org.jivesoftware.smack.util.XmlStringBuilder;
5 | import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
6 |
7 | public class BuddycloudAffiliation implements PacketExtension {
8 |
9 | public static final String ELEMENT_NAME = "affiliation";
10 |
11 | protected String node;
12 | protected Type type;
13 |
14 | public enum Type {
15 | member, none, outcast, owner, publisher, moderator, followerPlus
16 | }
17 |
18 | public BuddycloudAffiliation(String nodeId, Type affiliation) {
19 | node = nodeId;
20 | type = affiliation;
21 | }
22 |
23 | public String getNodeId() {
24 | return node;
25 | }
26 |
27 | public Type getType() {
28 | return type;
29 | }
30 |
31 | public String getElementName() {
32 | return ELEMENT_NAME;
33 | }
34 |
35 | public String getNamespace() {
36 | return PubSubNamespace.OWNER.getXmlns();
37 | }
38 |
39 | @Override
40 | public CharSequence toXML() {
41 | XmlStringBuilder xml = new XmlStringBuilder();
42 | xml.halfOpenElement(getElementName());
43 | xml.optAttribute("node", node);
44 | xml.optAttribute(ELEMENT_NAME, type.toString());
45 | xml.closeEmptyElement();
46 | return xml;
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/handler/response/ContentData.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.handler.response;
17 |
18 | import com.buddycloud.channeldirectory.search.rsm.RSM;
19 |
20 | /**
21 | * Content query response in RSMable format.
22 | * Must have an identifier for indexing and paging purposes.
23 | *
24 | * @see RSM
25 | */
26 | public class ContentData {
27 |
28 | private String id;
29 | private String type;
30 |
31 | public void setType(String type) {
32 | this.type = type;
33 | }
34 |
35 | public String getType() {
36 | return type;
37 | }
38 |
39 | public String getId() {
40 | return id;
41 | }
42 |
43 | public void setId(String id) {
44 | this.id = id;
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/commons/solr/SolrUtils.java:
--------------------------------------------------------------------------------
1 | package com.buddycloud.channeldirectory.commons.solr;
2 |
3 | import java.util.Date;
4 |
5 | import org.apache.solr.common.SolrDocument;
6 |
7 | import com.buddycloud.channeldirectory.search.handler.response.ChannelData;
8 | import com.buddycloud.channeldirectory.search.handler.response.Geolocation;
9 |
10 | public class SolrUtils {
11 |
12 | public static ChannelData convertToChannelData(SolrDocument solrDocument) {
13 | ChannelData channelData = new ChannelData();
14 | String latLonStr = (String) solrDocument.getFieldValue("geoloc");
15 | if (latLonStr != null) {
16 | String[] latLonSplit = latLonStr.split(",");
17 | channelData.setGeolocation(new Geolocation(
18 | Double.parseDouble(latLonSplit[0]),
19 | Double.parseDouble(latLonSplit[1])));
20 | }
21 |
22 | channelData.setCreationDate((Date) solrDocument.getFieldValue("creation-date"));
23 | channelData.setChannelType((String) solrDocument.getFieldValue("channel-type"));
24 | channelData.setId((String) solrDocument.getFieldValue("jid"));
25 | channelData.setTitle((String) solrDocument.getFieldValue("title"));
26 | channelData.setDescription((String) solrDocument.getFieldValue("description"));
27 | channelData.setDefaultAffiliation((String) solrDocument.getFieldValue("default-affiliation"));
28 |
29 | return channelData;
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=DEBUG, FILE
2 |
3 | log4j.logger.com.buddycloud.channeldirectory.crawler=DEBUG, CRAWLERFILE
4 | log4j.logger.com.buddycloud.channeldirectory.search=DEBUG, SEARCHFILE
5 |
6 | log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
7 | log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
8 | log4j.appender.CONSOLE.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
9 |
10 | log4j.appender.FILE=org.apache.log4j.RollingFileAppender
11 | log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
12 | log4j.appender.FILE.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
13 | log4j.appender.FILE.File=logs/log
14 |
15 | log4j.appender.SEARCHFILE=org.apache.log4j.RollingFileAppender
16 | log4j.appender.SEARCHFILE.layout=org.apache.log4j.PatternLayout
17 | log4j.appender.SEARCHFILE.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
18 | log4j.appender.SEARCHFILE.File=logs/search.log
19 |
20 | log4j.appender.CRAWLERFILE=org.apache.log4j.RollingFileAppender
21 | log4j.appender.CRAWLERFILE.layout=org.apache.log4j.PatternLayout
22 | log4j.appender.CRAWLERFILE.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
23 | log4j.appender.CRAWLERFILE.File=logs/crawler.log
24 |
25 | log4j.appender.SYSLOG=org.apache.log4j.net.SyslogAppender
26 | log4j.appender.SYSLOG.syslogHost=127.0.0.1
27 | log4j.appender.SYSLOG.layout=org.apache.log4j.PatternLayout
28 | log4j.appender.SYSLOG.layout.ConversionPattern=%-5p %t: %c{1} - %m
29 | log4j.appender.SYSLOG.Facility=USER
--------------------------------------------------------------------------------
/resources/solr/multicore/channels/conf/stopwords.txt:
--------------------------------------------------------------------------------
1 | # Licensed to the Apache Software Foundation (ASF) under one or more
2 | # contributor license agreements. See the NOTICE file distributed with
3 | # this work for additional information regarding copyright ownership.
4 | # The ASF licenses this file to You under the Apache License, Version 2.0
5 | # (the "License"); you may not use this file except in compliance with
6 | # the License. You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | #-----------------------------------------------------------------------
17 | # a couple of test stopwords to test that the words are really being
18 | # configured from this file:
19 | stopworda
20 | stopwordb
21 |
22 | #Standard english stop words taken from Lucene's StopAnalyzer
23 | a
24 | an
25 | and
26 | are
27 | as
28 | at
29 | be
30 | but
31 | by
32 | for
33 | if
34 | in
35 | into
36 | is
37 | it
38 | no
39 | not
40 | of
41 | on
42 | or
43 | s
44 | such
45 | t
46 | that
47 | the
48 | their
49 | then
50 | there
51 | these
52 | they
53 | this
54 | to
55 | was
56 | will
57 | with
58 |
59 |
--------------------------------------------------------------------------------
/resources/solr/multicore/posts/conf/stopwords.txt:
--------------------------------------------------------------------------------
1 | # Licensed to the Apache Software Foundation (ASF) under one or more
2 | # contributor license agreements. See the NOTICE file distributed with
3 | # this work for additional information regarding copyright ownership.
4 | # The ASF licenses this file to You under the Apache License, Version 2.0
5 | # (the "License"); you may not use this file except in compliance with
6 | # the License. You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | #-----------------------------------------------------------------------
17 | # a couple of test stopwords to test that the words are really being
18 | # configured from this file:
19 | stopworda
20 | stopwordb
21 |
22 | #Standard english stop words taken from Lucene's StopAnalyzer
23 | a
24 | an
25 | and
26 | are
27 | as
28 | at
29 | be
30 | but
31 | by
32 | for
33 | if
34 | in
35 | into
36 | is
37 | it
38 | no
39 | not
40 | of
41 | on
42 | or
43 | s
44 | such
45 | t
46 | that
47 | the
48 | their
49 | then
50 | there
51 | these
52 | they
53 | this
54 | to
55 | was
56 | will
57 | with
58 |
59 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/utils/GeolocationUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.utils;
17 |
18 | import org.dom4j.Element;
19 |
20 | import com.buddycloud.channeldirectory.search.handler.response.Geolocation;
21 |
22 | public class GeolocationUtils {
23 |
24 | public static void appendGeoLocation(Element geoElement, Geolocation geoLocation) {
25 |
26 | if (geoElement == null || geoLocation == null) {
27 | return;
28 | }
29 |
30 | if (geoLocation.getLat() != null) {
31 | geoElement.addElement("lat").setText(
32 | geoLocation.getLat().toString());
33 | }
34 |
35 | if (geoLocation.getLng() != null) {
36 | geoElement.addElement("lon").setText(
37 | geoLocation.getLng().toString());
38 | }
39 |
40 | if (geoLocation.getText() != null) {
41 | geoElement.addElement("text").setText(
42 | geoLocation.getText());
43 | }
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/crawler/node/NodeCrawler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.crawler.node;
17 |
18 | import org.jivesoftware.smackx.pubsub.BuddycloudNode;
19 | import org.jivesoftware.smackx.pubsub.Node;
20 |
21 | /**
22 | * Implementations of this interface are responsible for
23 | * crawling a {@link Node} in a specific interest context.
24 | *
25 | */
26 | public interface NodeCrawler {
27 |
28 | /**
29 | * Retrieves information from a {@link Node} and
30 | * commits it into the channel directory database.
31 | *
32 | * @param node
33 | * @param server
34 | * @throws Exception
35 | */
36 | void crawl(BuddycloudNode node, String server) throws Exception;
37 |
38 |
39 | /**
40 | * Returns whether a {@link Node} should be processed
41 | * by this {@link NodeCrawler}
42 | *
43 | * @param node
44 | * @return
45 | */
46 | boolean accept(BuddycloudNode node);
47 | }
48 |
--------------------------------------------------------------------------------
/resources/solr/multicore/solr.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
25 |
26 |
27 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/handler/response/Geolocation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.handler.response;
17 |
18 | /**
19 | * Represents a Latitude/Longitude location pair,
20 | * and a text representation of a location
21 | *
22 | */
23 | public class Geolocation {
24 |
25 | public static final String NAMESPACE = "http://jabber.org/protocol/geoloc";
26 |
27 | private Double lat;
28 | private Double lng;
29 | private String text;
30 |
31 | public Geolocation() {}
32 |
33 | public Geolocation(Double lat, Double lng) {
34 | this.lat = lat;
35 | this.lng = lng;
36 | }
37 |
38 | public void setLat(Double lat) {
39 | this.lat = lat;
40 | }
41 |
42 | public Double getLat() {
43 | return lat;
44 | }
45 |
46 | public void setLng(Double lng) {
47 | this.lng = lng;
48 | }
49 |
50 | public Double getLng() {
51 | return lng;
52 | }
53 |
54 | public void setText(String text) {
55 | this.text = text;
56 | }
57 |
58 | public String getText() {
59 | return text;
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/handler/response/FakeDataGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.handler.response;
17 |
18 | import java.util.ArrayList;
19 | import java.util.List;
20 |
21 |
22 | public class FakeDataGenerator {
23 |
24 | public static List createFakeChannels() {
25 |
26 | List fakeList = new ArrayList();
27 |
28 | ChannelData object1 = new ChannelData();
29 | object1.setGeolocation(new Geolocation(45.44, 12.33));
30 | object1.setId("topicchanne01@example.org");
31 | object1.setTitle("A channel about topic 01");
32 | fakeList.add(object1);
33 |
34 | ChannelData object2 = new ChannelData();
35 | object2.setGeolocation(new Geolocation(45.44, 12.33));
36 | object2.setId("topicchanne02@example.org");
37 | object2.setTitle("A channel about topic 02");
38 | fakeList.add(object2);
39 |
40 | return fakeList;
41 | }
42 |
43 | public static List createFakePosts() {
44 |
45 | List fakeList = new ArrayList();
46 | return fakeList;
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/resources/schema/create-schema.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE subscribed_server (
2 | name VARCHAR(300),
3 | PRIMARY KEY (name)
4 | );
5 |
6 | CREATE TABLE subscribed_node (
7 | name VARCHAR(300),
8 | server VARCHAR(300),
9 | metadata_updated TIMESTAMP,
10 | subscribers_updated TIMESTAMP,
11 | items_crawled TIMESTAMP,
12 | PRIMARY KEY (name, server)
13 | );
14 |
15 | CREATE SEQUENCE user_id_seq;
16 | CREATE TABLE t_user (
17 | id BIGINT PRIMARY KEY DEFAULT nextval('user_id_seq'),
18 | jid VARCHAR(300)
19 | );
20 | CREATE INDEX user_jid_index ON t_user(jid);
21 |
22 | CREATE SEQUENCE item_id_seq;
23 | CREATE TABLE item (
24 | id BIGINT PRIMARY KEY DEFAULT nextval('item_id_seq'),
25 | jid VARCHAR(300),
26 | title VARCHAR(300),
27 | description VARCHAR(500)
28 | );
29 | CREATE INDEX item_jid_index ON item(jid);
30 |
31 | CREATE TABLE taste_preferences (
32 | user_id BIGINT NOT NULL,
33 | item_id BIGINT NOT NULL,
34 | PRIMARY KEY (user_id, item_id)
35 | );
36 |
37 | CREATE INDEX taste_preferences_user_id_index ON taste_preferences (user_id);
38 | CREATE INDEX taste_preferences_item_id_index ON taste_preferences (item_id);
39 |
40 | CREATE TABLE taste_item_similarity (
41 | item_id_a BIGINT NOT NULL,
42 | item_id_b BIGINT NOT NULL,
43 | similarity FLOAT NOT NULL,
44 | PRIMARY KEY (item_id_a, item_id_b)
45 | );
46 |
47 | CREATE TABLE channel_activity (
48 | channel_jid VARCHAR(300),
49 | detailed_activity VARCHAR(2048),
50 | summarized_activity BIGINT,
51 | updated TIMESTAMP,
52 | earliest TIMESTAMP,
53 | PRIMARY KEY (channel_jid)
54 | );
55 |
56 | CREATE INDEX channel_activity_summary_index ON channel_activity (summarized_activity DESC);
57 | CREATE INDEX channel_activity_updated_index ON channel_activity (updated DESC);
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/handler/AbstractQueryHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.handler;
17 |
18 | import java.util.Properties;
19 |
20 | import org.apache.log4j.Logger;
21 |
22 | /**
23 | * Generic QueryHandler.
24 | * QueryHandler implementations should extend this class.
25 | *
26 | * @see QueryHandler
27 | *
28 | */
29 | public abstract class AbstractQueryHandler implements QueryHandler {
30 |
31 | private final String namespace;
32 | private final Logger logger;
33 | private final Properties properties;
34 |
35 | /**
36 | * Creates a QueryHandler for a given namespace
37 | * @param namespace
38 | */
39 | public AbstractQueryHandler(String namespace, Properties properties) {
40 | this.namespace = namespace;
41 | this.properties = properties;
42 | this.logger = Logger.getLogger(getClass());
43 | }
44 |
45 | @Override
46 | public String getNamespace() {
47 | return namespace;
48 | }
49 |
50 | protected Logger getLogger() {
51 | return logger;
52 | }
53 |
54 | protected Properties getProperties() {
55 | return properties;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/test/java/com/buddycloud/HSQLDBTest.java:
--------------------------------------------------------------------------------
1 | package com.buddycloud;
2 |
3 | import java.beans.PropertyVetoException;
4 | import java.io.FileInputStream;
5 | import java.io.FileNotFoundException;
6 | import java.io.IOException;
7 | import java.sql.SQLException;
8 | import java.sql.Statement;
9 | import java.util.Properties;
10 |
11 | import org.apache.commons.io.IOUtils;
12 | import org.junit.After;
13 | import org.junit.Before;
14 |
15 | import com.buddycloud.channeldirectory.commons.db.ChannelDirectoryDataSource;
16 |
17 | public class HSQLDBTest {
18 |
19 | private ChannelDirectoryDataSource dataSource;
20 |
21 | @Before
22 | public void setUpDB() throws Exception {
23 | Properties p = new Properties();
24 | p.setProperty("mahout.jdbc.url", "jdbc:hsqldb:mem:channels;create=true");
25 | p.setProperty("mahout.jdbc.driver", "org.hsqldb.jdbcDriver");
26 | this.dataSource = new ChannelDirectoryDataSource(p);
27 |
28 | runBatch("resources/schema/create-schema.sql");
29 | runBatch("resources/schema/update-schema-0.sql");
30 | }
31 |
32 | @After
33 | public void tearDownDB() throws Exception {
34 | runBatch("resources/schema/drop-schema.sql");
35 | }
36 |
37 | private void runBatch(String batchFile) throws PropertyVetoException,
38 | SQLException, IOException, FileNotFoundException {
39 | Statement st = dataSource.createStatement();
40 | String schemaStr = IOUtils.toString(new FileInputStream(batchFile));
41 | st.addBatch("SET DATABASE SQL SYNTAX PGS TRUE");
42 | for (String sqlStr : schemaStr.split(";")) {
43 | if (sqlStr.trim().length() > 0) {
44 | st.addBatch(sqlStr);
45 | }
46 | }
47 | st.executeBatch();
48 | ChannelDirectoryDataSource.close(st);
49 | }
50 |
51 | public ChannelDirectoryDataSource getDataSource() {
52 | return dataSource;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/commons/solr/SolrServerFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.commons.solr;
17 |
18 | import java.net.MalformedURLException;
19 | import java.util.Properties;
20 |
21 | import org.apache.solr.client.solrj.SolrServer;
22 | import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
23 |
24 | public class SolrServerFactory {
25 |
26 | private static final String SOLR_CHANNELCORE_PROP = "solr.channelcore";
27 | private static final String SOLR_POSTCORE_PROP = "solr.postcore";
28 |
29 | private static SolrServer createSolrCore(Properties properties,
30 | String coreProperty) throws MalformedURLException {
31 | String solrChannelUrl = (String) properties.get(coreProperty);
32 | return new CommonsHttpSolrServer(solrChannelUrl);
33 | }
34 |
35 | public SolrServer createChannelCore(Properties properties)
36 | throws MalformedURLException {
37 | return createSolrCore(properties, SOLR_CHANNELCORE_PROP);
38 | }
39 |
40 | public SolrServer createPostCore(Properties properties)
41 | throws MalformedURLException {
42 | return createSolrCore(properties, SOLR_POSTCORE_PROP);
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/commons/ConfigurationUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.commons;
17 |
18 | import java.io.FileInputStream;
19 | import java.io.IOException;
20 | import java.util.Properties;
21 |
22 | import org.apache.log4j.Logger;
23 |
24 | /**
25 | * General utils for accessing the engine configuration
26 | *
27 | */
28 | public class ConfigurationUtils {
29 |
30 | private static final String CONFIGURATION_FILE = getChannelDirHome()
31 | + "/configuration.properties";
32 |
33 | private static Logger LOGGER = Logger.getLogger(ConfigurationUtils.class);
34 |
35 | public static Properties loadConfiguration() throws IOException {
36 | Properties configuration = new Properties();
37 | try {
38 | configuration.load(new FileInputStream(CONFIGURATION_FILE));
39 | } catch (IOException e) {
40 | LOGGER.fatal("Configuration could not be loaded.", e);
41 | throw e;
42 | }
43 | return configuration;
44 | }
45 |
46 |
47 | public static String getChannelDirHome() {
48 | String channelDirHome = System.getenv("CHANNEL_DIRECTORY_HOME");
49 | return channelDirHome == null ? "." : channelDirHome;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/bin/start-solr.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | rem Licensed to the Apache Software Foundation (ASF) under one or more
3 | rem contributor license agreements. See the NOTICE file distributed with
4 | rem this work for additional information regarding copyright ownership.
5 | rem The ASF licenses this file to You under the Apache License, Version 2.0
6 | rem (the "License"); you may not use this file except in compliance with
7 | rem the License. You may obtain a copy of the License at
8 | rem
9 | rem http://www.apache.org/licenses/LICENSE-2.0
10 | rem
11 | rem Unless required by applicable law or agreed to in writing, software
12 | rem distributed under the License is distributed on an "AS IS" BASIS,
13 | rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | rem See the License for the specific language governing permissions and
15 | rem limitations under the License.
16 |
17 | rem ---------------------------------------------------------------------------
18 | rem Start script for the Channel Directory Solr
19 | rem ---------------------------------------------------------------------------
20 |
21 | rem Guess CHANNEL_DIRECTORY_HOME if not defined
22 | set CURRENT_DIR=%cd%
23 | if not "%CHANNEL_DIRECTORY_HOME%" == "" goto gotHome
24 | set CHANNEL_DIRECTORY_HOME=%CURRENT_DIR%
25 | if exist "%CHANNEL_DIRECTORY_HOME%\resources\solr\start.jar" goto okHome
26 | cd ..
27 | set CHANNEL_DIRECTORY_HOME=%cd%
28 | cd %CURRENT_DIR%
29 | :gotHome
30 | if exist "%CHANNEL_DIRECTORY_HOME%\resources\solr\start.jar" goto okHome
31 | echo The CHANNEL_DIRECTORY_HOME environment variable is not defined correctly
32 | echo This environment variable is needed to run this program
33 | goto end
34 | :okHome
35 |
36 | rem Go to Solr home and start it
37 | cd %CHANNEL_DIRECTORY_HOME%\resources\solr
38 | java -Dsolr.solr.home=multicore -jar start.jar
39 |
40 | :end
--------------------------------------------------------------------------------
/bin/start-crawler.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | rem Licensed to the Apache Software Foundation (ASF) under one or more
3 | rem contributor license agreements. See the NOTICE file distributed with
4 | rem this work for additional information regarding copyright ownership.
5 | rem The ASF licenses this file to You under the Apache License, Version 2.0
6 | rem (the "License"); you may not use this file except in compliance with
7 | rem the License. You may obtain a copy of the License at
8 | rem
9 | rem http://www.apache.org/licenses/LICENSE-2.0
10 | rem
11 | rem Unless required by applicable law or agreed to in writing, software
12 | rem distributed under the License is distributed on an "AS IS" BASIS,
13 | rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | rem See the License for the specific language governing permissions and
15 | rem limitations under the License.
16 |
17 | rem ---------------------------------------------------------------------------
18 | rem Start script for the Channel Directory Crawler
19 | rem ---------------------------------------------------------------------------
20 |
21 | rem Guess CHANNEL_DIRECTORY_HOME if not defined
22 | set CURRENT_DIR=%cd%
23 | if not "%CHANNEL_DIRECTORY_HOME%" == "" goto gotHome
24 | set CHANNEL_DIRECTORY_HOME=%CURRENT_DIR%
25 | if exist "%CHANNEL_DIRECTORY_HOME%\lib\channel-directory.jar" goto okHome
26 | cd ..
27 | set CHANNEL_DIRECTORY_HOME=%cd%
28 | cd %CURRENT_DIR%
29 | :gotHome
30 | if exist "%CHANNEL_DIRECTORY_HOME%\lib\channel-directory.jar" goto okHome
31 | echo The CHANNEL_DIRECTORY_HOME environment variable is not defined correctly
32 | echo This environment variable is needed to run this program
33 | goto end
34 | :okHome
35 |
36 | rem Start the search engine
37 | cd %CHANNEL_DIRECTORY_HOME%
38 | java -cp .;.\*;.\lib\* com.buddycloud.channeldirectory.crawler.Main
39 |
40 | :end
--------------------------------------------------------------------------------
/bin/start-search.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | rem Licensed to the Apache Software Foundation (ASF) under one or more
3 | rem contributor license agreements. See the NOTICE file distributed with
4 | rem this work for additional information regarding copyright ownership.
5 | rem The ASF licenses this file to You under the Apache License, Version 2.0
6 | rem (the "License"); you may not use this file except in compliance with
7 | rem the License. You may obtain a copy of the License at
8 | rem
9 | rem http://www.apache.org/licenses/LICENSE-2.0
10 | rem
11 | rem Unless required by applicable law or agreed to in writing, software
12 | rem distributed under the License is distributed on an "AS IS" BASIS,
13 | rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | rem See the License for the specific language governing permissions and
15 | rem limitations under the License.
16 |
17 | rem ---------------------------------------------------------------------------
18 | rem Start script for the Channel Directory Search Engine
19 | rem ---------------------------------------------------------------------------
20 |
21 | rem Guess CHANNEL_DIRECTORY_HOME if not defined
22 | set CURRENT_DIR=%cd%
23 | if not "%CHANNEL_DIRECTORY_HOME%" == "" goto gotHome
24 | set CHANNEL_DIRECTORY_HOME=%CURRENT_DIR%
25 | if exist "%CHANNEL_DIRECTORY_HOME%\lib\channel-directory.jar" goto okHome
26 | cd ..
27 | set CHANNEL_DIRECTORY_HOME=%cd%
28 | cd %CURRENT_DIR%
29 | :gotHome
30 | if exist "%CHANNEL_DIRECTORY_HOME%\lib\channel-directory.jar" goto okHome
31 | echo The CHANNEL_DIRECTORY_HOME environment variable is not defined correctly
32 | echo This environment variable is needed to run this program
33 | goto end
34 | :okHome
35 |
36 | rem Start the search engine
37 | cd %CHANNEL_DIRECTORY_HOME%
38 | java -cp .;.\*;.\lib\* com.buddycloud.channeldirectory.search.Main
39 |
40 | :end
--------------------------------------------------------------------------------
/bin/setup-schema.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | rem Licensed to the Apache Software Foundation (ASF) under one or more
3 | rem contributor license agreements. See the NOTICE file distributed with
4 | rem this work for additional information regarding copyright ownership.
5 | rem The ASF licenses this file to You under the Apache License, Version 2.0
6 | rem (the "License"); you may not use this file except in compliance with
7 | rem the License. You may obtain a copy of the License at
8 | rem
9 | rem http://www.apache.org/licenses/LICENSE-2.0
10 | rem
11 | rem Unless required by applicable law or agreed to in writing, software
12 | rem distributed under the License is distributed on an "AS IS" BASIS,
13 | rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | rem See the License for the specific language governing permissions and
15 | rem limitations under the License.
16 |
17 | rem ---------------------------------------------------------------------------
18 | rem Start script for the Channel Directory Search Engine
19 | rem ---------------------------------------------------------------------------
20 |
21 | rem Guess CHANNEL_DIRECTORY_HOME if not defined
22 | set CURRENT_DIR=%cd%
23 | if not "%CHANNEL_DIRECTORY_HOME%" == "" goto gotHome
24 | set CHANNEL_DIRECTORY_HOME=%CURRENT_DIR%
25 | if exist "%CHANNEL_DIRECTORY_HOME%\lib\channel-directory.jar" goto okHome
26 | cd ..
27 | set CHANNEL_DIRECTORY_HOME=%cd%
28 | cd %CURRENT_DIR%
29 | :gotHome
30 | if exist "%CHANNEL_DIRECTORY_HOME%\lib\channel-directory.jar" goto okHome
31 | echo The CHANNEL_DIRECTORY_HOME environment variable is not defined correctly
32 | echo This environment variable is needed to run this program
33 | goto end
34 | :okHome
35 |
36 | rem Start the search engine
37 | cd %CHANNEL_DIRECTORY_HOME%
38 | java -cp .;.\*;.\lib\* com.buddycloud.channeldirectory.commons.db.CreateSchema
39 |
40 | :end
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/handler/common/mahout/RecommendationResponse.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.handler.common.mahout;
17 |
18 | import java.util.List;
19 |
20 | import com.buddycloud.channeldirectory.search.handler.response.ChannelData;
21 |
22 | /**
23 | *
24 | */
25 | public class RecommendationResponse {
26 |
27 | private List response;
28 | private int numFound;
29 |
30 | /**
31 | * @param response
32 | * @param numFound
33 | */
34 | public RecommendationResponse(List response, int numFound) {
35 | this.response = response;
36 | this.numFound = numFound;
37 | }
38 |
39 | /**
40 | * @return the response
41 | */
42 | public List getResponse() {
43 | return response;
44 | }
45 |
46 | /**
47 | * @param response the response to set
48 | */
49 | public void setResponse(List response) {
50 | this.response = response;
51 | }
52 |
53 | /**
54 | * @return the numFound
55 | */
56 | public int getNumFound() {
57 | return numFound;
58 | }
59 |
60 | /**
61 | * @param numFound the numFound to set
62 | */
63 | public void setNumFound(int numFound) {
64 | this.numFound = numFound;
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/crawler/PubSubManagers.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.crawler;
17 |
18 | import java.util.HashMap;
19 | import java.util.Map;
20 |
21 | import org.jivesoftware.smack.XMPPConnection;
22 | import org.jivesoftware.smackx.pubsub.BuddycloudPubsubManager;
23 | import org.jivesoftware.smackx.pubsub.PubSubManager;
24 |
25 | /**
26 | * Simply maintain a collection of {@link PubSubManager},
27 | * so different crawling strategies can use the same
28 | * node cache.
29 | *
30 | */
31 | public class PubSubManagers {
32 |
33 | private final Map pubSubManagers = new HashMap();
34 | private final XMPPConnection connection;
35 |
36 | public PubSubManagers(XMPPConnection connection) {
37 | this.connection = connection;
38 | }
39 |
40 | public BuddycloudPubsubManager getPubSubManager(String pubSubServer) {
41 | BuddycloudPubsubManager pubSubManager = pubSubManagers.get(pubSubServer);
42 | if (pubSubManager == null) {
43 | pubSubManager = new BuddycloudPubsubManager(connection, pubSubServer);
44 | pubSubManagers.put(pubSubServer, pubSubManager);
45 | }
46 | return pubSubManager;
47 | }
48 |
49 | /**
50 | * @return
51 | */
52 | public XMPPConnection getConnection() {
53 | return connection;
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/handler/common/mahout/ChannelRecommenderDataModel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.handler.common.mahout;
17 |
18 | import org.apache.mahout.cf.taste.model.DataModel;
19 |
20 | import com.buddycloud.channeldirectory.search.handler.response.ChannelData;
21 |
22 | /**
23 | * Implementations should embed a Mahout data model,
24 | * and also should be responsible for translating
25 | * Mahout-specific ids to jids.
26 | *
27 | */
28 | public interface ChannelRecommenderDataModel {
29 |
30 | /**
31 | * Returns a Mahout {@link DataModel},
32 | * which is required by the recommender.
33 | *
34 | * @return
35 | */
36 | public DataModel getDataModel();
37 |
38 | /**
39 | * Converts a user jid into a long id,
40 | * which is required by Mahout.
41 | *
42 | * @param userJid
43 | * @return
44 | */
45 | public Long toUserId(String userJid);
46 |
47 | /**
48 | * Given the Mahout long id for an item,
49 | * returns the respective channel data.
50 | *
51 | * @param itemID
52 | * @return
53 | */
54 | public ChannelData toChannelData(long itemID);
55 |
56 | /**
57 | * Converts a channel jid into a long id,
58 | * which is required by Mahout.
59 | *
60 | * @param channelJid
61 | * @return
62 | */
63 | public Long toChannelId(String channelJid);
64 |
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/cli/QueryToDBMS.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.cli;
17 |
18 | import java.sql.PreparedStatement;
19 | import java.sql.ResultSet;
20 | import java.sql.SQLException;
21 | import java.util.Properties;
22 |
23 | import com.buddycloud.channeldirectory.commons.db.ChannelDirectoryDataSource;
24 | import com.mchange.v2.c3p0.DataSources;
25 |
26 | /**
27 | * @author Abmar
28 | *
29 | */
30 | public class QueryToDBMS implements Query {
31 |
32 | private String sql;
33 |
34 | public QueryToDBMS(String sql) {
35 | this.sql = sql;
36 | }
37 |
38 | /* (non-Javadoc)
39 | * @see com.buddycloud.channeldirectory.cli.Query#exec(java.lang.String, java.util.Properties)
40 | */
41 | @Override
42 | public String exec(String args, Properties configuration) throws Exception {
43 |
44 | ChannelDirectoryDataSource dataSource = new ChannelDirectoryDataSource(configuration);
45 | PreparedStatement statement = null;
46 | try {
47 | statement = dataSource.prepareStatement(sql);
48 | ResultSet resultSet = statement.executeQuery();
49 | if (!resultSet.next()) {
50 | return "";
51 | }
52 | return resultSet.getString(1);
53 |
54 | } catch (SQLException e1) {
55 | throw e1;
56 | } finally {
57 | ChannelDirectoryDataSource.close(statement);
58 | DataSources.destroy(dataSource.getDataSource());
59 | }
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/cli/QueryToSolr.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.cli;
17 |
18 | import java.util.Properties;
19 |
20 | import org.apache.solr.client.solrj.SolrQuery;
21 | import org.apache.solr.client.solrj.SolrServer;
22 | import org.apache.solr.client.solrj.response.QueryResponse;
23 |
24 | import com.buddycloud.channeldirectory.commons.solr.SolrServerFactory;
25 |
26 | /**
27 | * @author Abmar
28 | *
29 | */
30 | public class QueryToSolr implements Query {
31 |
32 | private final String agg;
33 | private final String core;
34 | private final String q;
35 |
36 | public QueryToSolr(String agg, String core, String q) {
37 | this.agg = agg;
38 | this.core = core;
39 | this.q = q;
40 | }
41 |
42 | public String exec(String args, Properties configuration) throws Exception {
43 |
44 | SolrServer solrServer = null;
45 |
46 | if (core.equals("posts")) {
47 | solrServer = new SolrServerFactory().createPostCore(configuration);
48 | } else if (core.equals("channels")) {
49 | solrServer = new SolrServerFactory().createChannelCore(configuration);
50 | }
51 |
52 | SolrQuery solrQuery = new SolrQuery(q);
53 | QueryResponse queryResponse = solrServer.query(solrQuery);
54 |
55 | if (agg.equals("count")) {
56 | Long numFound = queryResponse.getResults().getNumFound();
57 | return numFound.toString();
58 | }
59 |
60 | return null;
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/resources/solr/multicore/posts/conf/solrconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
23 |
24 | LUCENE_31
25 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | solr
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/resources/solr/multicore/channels/conf/solrconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
23 |
24 | LUCENE_31
25 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | solr
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/rsm/RSM.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.rsm;
17 |
18 | /**
19 | * Represents a container for attributes related
20 | * to the RSM format (http://xmpp.org/extensions/xep-0059.html).
21 | *
22 | */
23 | public class RSM {
24 |
25 | public static String NAMESPACE = "http://jabber.org/protocol/rsm";
26 |
27 | private Integer max;
28 | private Integer index = 0;
29 | private String before;
30 | private String after;
31 |
32 | private String first;
33 | private String last;
34 | private Integer count;
35 |
36 | public String getFirst() {
37 | return first;
38 | }
39 |
40 | public void setFirst(String first) {
41 | this.first = first;
42 | }
43 |
44 | public String getLast() {
45 | return last;
46 | }
47 |
48 | public void setLast(String last) {
49 | this.last = last;
50 | }
51 |
52 | public Integer getCount() {
53 | return count;
54 | }
55 |
56 | public void setCount(Integer count) {
57 | this.count = count;
58 | }
59 |
60 | public void setMax(Integer max) {
61 | this.max = max;
62 | }
63 |
64 | public void setIndex(Integer index) {
65 | this.index = index;
66 | }
67 |
68 | public void setBefore(String before) {
69 | this.before = before;
70 | }
71 |
72 | public void setAfter(String after) {
73 | this.after = after;
74 | }
75 |
76 | public Integer getMax() {
77 | return max;
78 | }
79 |
80 | public Integer getIndex() {
81 | return index;
82 | }
83 |
84 | public String getBefore() {
85 | return before;
86 | }
87 |
88 | public String getAfter() {
89 | return after;
90 | }
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/rsm/SolrRSMUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.rsm;
17 |
18 | import org.apache.solr.client.solrj.SolrQuery;
19 | import org.apache.solr.client.solrj.response.QueryResponse;
20 |
21 |
22 | /**
23 | * It is responsible for providing utility methods related to RSM format
24 | * (http://xmpp.org/extensions/xep-0059.html),
25 | * which are used on the Solr query processing and response.
26 | *
27 | * @see RSM
28 | *
29 | */
30 | public class SolrRSMUtils {
31 |
32 | public static void preprocess(
33 | SolrQuery query, RSM rsm)
34 | throws IllegalArgumentException {
35 |
36 | String after = rsm.getAfter();
37 | String before = rsm.getBefore();
38 |
39 | int initialIndex = rsm.getIndex();
40 | int lastIndex = -1;
41 |
42 | if (after != null) {
43 | initialIndex = Integer.valueOf(after);
44 | }
45 | if (before != null && !before.isEmpty()) {
46 | lastIndex = Integer.valueOf(before) - 2;
47 | }
48 |
49 | if (rsm.getMax() != null) {
50 | if (before != null) {
51 | initialIndex = lastIndex - rsm.getMax() + 1;
52 | } else {
53 | lastIndex = initialIndex + rsm.getMax() - 1;
54 | }
55 | }
56 |
57 | if (lastIndex >= 0) {
58 | query.setStart(initialIndex);
59 | query.setRows(lastIndex - initialIndex + 1);
60 | }
61 |
62 | rsm.setIndex(initialIndex);
63 | rsm.setFirst(String.valueOf(initialIndex + 1));
64 | rsm.setLast(String.valueOf(lastIndex + 1));
65 | }
66 |
67 | public static void postprocess(
68 | QueryResponse queryResponse, RSM rsm)
69 | throws IllegalArgumentException {
70 |
71 | rsm.setCount((int)queryResponse.getResults().getNumFound());
72 |
73 | if (queryResponse.getResponse().size() == 0) {
74 | rsm.setFirst(null);
75 | rsm.setLast(null);
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/main/java/org/jivesoftware/smackx/pubsub/BuddycloudPubsubManager.java:
--------------------------------------------------------------------------------
1 | package org.jivesoftware.smackx.pubsub;
2 |
3 | import org.jivesoftware.smack.SmackException.NoResponseException;
4 | import org.jivesoftware.smack.SmackException.NotConnectedException;
5 | import org.jivesoftware.smack.XMPPConnection;
6 | import org.jivesoftware.smack.XMPPException.XMPPErrorException;
7 | import org.jivesoftware.smack.provider.ProviderManager;
8 | import org.jivesoftware.smackx.disco.packet.DiscoverItems;
9 | import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
10 |
11 | public class BuddycloudPubsubManager {
12 |
13 | static {
14 | // Use the BuddycloudAffiliationsProvider
15 | BuddycloudAffiliationsProvider affiliationsProvider = new BuddycloudAffiliationsProvider();
16 | ProviderManager.addExtensionProvider(BuddycloudAffiliations.ELEMENT_NAME,
17 | PubSubNamespace.OWNER.getXmlns(), affiliationsProvider);
18 | ProviderManager.addExtensionProvider(BuddycloudAffiliations.ELEMENT_NAME,
19 | PubSubNamespace.BASIC.getXmlns(), affiliationsProvider);
20 |
21 | // Use the BuddycloudAffiliationProvider for buddycloud-specific affiliations
22 | BuddycloudAffiliationProvider affiliationProvider = new BuddycloudAffiliationProvider();
23 | ProviderManager.addExtensionProvider(BuddycloudAffiliation.ELEMENT_NAME,
24 | PubSubNamespace.OWNER.getXmlns(), affiliationProvider);
25 | ProviderManager.addExtensionProvider(BuddycloudAffiliation.ELEMENT_NAME,
26 | PubSubNamespace.BASIC.getXmlns(), affiliationProvider);
27 | }
28 |
29 | private final PubSubManager manager;
30 | private XMPPConnection connection;
31 | private final String toAddress;
32 |
33 | public BuddycloudPubsubManager(XMPPConnection connection, String toAddress) {
34 | this.manager = new PubSubManager(connection, toAddress);
35 | this.connection = connection;
36 | this.toAddress = toAddress;
37 | }
38 |
39 | public BuddycloudNode getNode(String id) throws NoResponseException,
40 | XMPPErrorException, NotConnectedException {
41 | return new BuddycloudNode(manager.getNode(id));
42 | }
43 |
44 | public DiscoverItems discoverNodes(String nodeId)
45 | throws NoResponseException, XMPPErrorException,
46 | NotConnectedException {
47 | return manager.discoverNodes(nodeId);
48 | }
49 |
50 | public BuddycloudNode getFirehoseNode() {
51 | BuddycloudFirehoseNode firehose = new BuddycloudFirehoseNode(connection);
52 | firehose.setTo(toAddress);
53 | return new BuddycloudNode(firehose);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/resources/init_d/buddycloud-solr:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 | # Original /etc/init.d/skeleton modified for http://mydebian.blogdns.org
3 |
4 | # PATH should only include /usr/* if it runs after the mountnfs.sh script
5 | PATH=/sbin:/usr/sbin:/bin:/usr/bin
6 | DESC="Buddycloud channel directory - Apache Solr"
7 | NAME="channeldirectory-solr"
8 | RUNFROM=/opt/buddycloud-channeldirectory/resources/solr
9 | DAEMON=/usr/bin/java
10 | DAEMON_ARGS="-Dsolr.solr.home=multicore -jar start.jar"
11 | PIDFILE=/var/run/$NAME.pid
12 | SCRIPTNAME=/etc/init.d/buddycloud-solr
13 |
14 | # the user that will run the script
15 | USER=buddycloud-channeldir
16 |
17 | # Make sure only root can run our script
18 | if [ "$(id -u)" != "0" ]; then
19 | echo "This script must be run as root. Try using sudo." 1>&2
20 | exit 1
21 | fi
22 |
23 |
24 | # NO NEED TO MODIFY THE LINES BELOW
25 |
26 | # Load the VERBOSE setting and other rcS variables
27 | . /lib/init/vars.sh
28 |
29 | # Define LSB log_* functions.
30 | # Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
31 | . /lib/lsb/init-functions
32 |
33 | #
34 | # Function that starts the daemon/service
35 | #
36 | do_start()
37 | {
38 |
39 | start-stop-daemon -b --start --quiet --chuid $USER --chdir $RUNFROM -m -p $PIDFILE --exec $DAEMON -- $DAEMON_ARGS \
40 | || return 2
41 | }
42 |
43 | #
44 | # Function that stops the daemon/service
45 | #
46 | do_stop()
47 | {
48 | start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE
49 | RETVAL="$?"
50 | rm -f $PIDFILE
51 | return "$RETVAL"
52 | }
53 |
54 | case "$1" in
55 | start)
56 | [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
57 | do_start
58 | case "$?" in
59 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
60 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
61 | esac
62 | ;;
63 | stop)
64 | [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
65 | do_stop
66 | case "$?" in
67 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
68 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
69 | esac
70 | ;;
71 | restart)
72 | #
73 | # If the "reload" option is implemented then remove the
74 | # 'force-reload' alias
75 | #
76 | log_daemon_msg "Restarting $DESC" "$NAME"
77 | do_stop
78 | case "$?" in
79 | 0|1)
80 | do_start
81 | case "$?" in
82 | 0) log_end_msg 0 ;;
83 | 1) log_end_msg 1 ;; # Old process is still running
84 | *) log_end_msg 1 ;; # Failed to start
85 | esac
86 | ;;
87 | *)
88 | # Failed to stop
89 | log_end_msg 1
90 | ;;
91 | esac
92 | ;;
93 | *)
94 | echo "Usage: $SCRIPTNAME {start|stop|restart}" >&2
95 | exit 3
96 | ;;
97 | esac
98 |
99 | :
--------------------------------------------------------------------------------
/resources/init_d/buddycloud-crawler:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 | # Original /etc/init.d/skeleton modified for http://mydebian.blogdns.org
3 |
4 | # PATH should only include /usr/* if it runs after the mountnfs.sh script
5 | PATH=/sbin:/usr/sbin:/bin:/usr/bin
6 | DESC="Buddycloud channel directory - Crawler"
7 | NAME="channeldirectory-crawler"
8 | RUNFROM=/opt/buddycloud-channeldirectory
9 | DAEMON=/usr/bin/java
10 | DAEMON_ARGS="-cp .:./*:./lib/* com.buddycloud.channeldirectory.crawler.Main"
11 | PIDFILE=/var/run/$NAME.pid
12 | SCRIPTNAME=/etc/init.d/buddycloud-crawler
13 |
14 | # the user that will run the script
15 | USER=buddycloud-channeldir
16 |
17 | # Make sure only root can run our script
18 | if [ "$(id -u)" != "0" ]; then
19 | echo "This script must be run as root. Try using sudo." 1>&2
20 | exit 1
21 | fi
22 |
23 |
24 | # NO NEED TO MODIFY THE LINES BELOW
25 |
26 | # Load the VERBOSE setting and other rcS variables
27 | . /lib/init/vars.sh
28 |
29 | # Define LSB log_* functions.
30 | # Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
31 | . /lib/lsb/init-functions
32 |
33 | #
34 | # Function that starts the daemon/service
35 | #
36 | do_start()
37 | {
38 |
39 | start-stop-daemon -b --start --quiet --chuid $USER --chdir $RUNFROM -m -p $PIDFILE --exec $DAEMON -- $DAEMON_ARGS \
40 | || return 2
41 | }
42 |
43 | #
44 | # Function that stops the daemon/service
45 | #
46 | do_stop()
47 | {
48 | start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE
49 | RETVAL="$?"
50 | rm -f $PIDFILE
51 | return "$RETVAL"
52 | }
53 |
54 | case "$1" in
55 | start)
56 | [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
57 | do_start
58 | case "$?" in
59 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
60 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
61 | esac
62 | ;;
63 | stop)
64 | [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
65 | do_stop
66 | case "$?" in
67 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
68 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
69 | esac
70 | ;;
71 | restart)
72 | #
73 | # If the "reload" option is implemented then remove the
74 | # 'force-reload' alias
75 | #
76 | log_daemon_msg "Restarting $DESC" "$NAME"
77 | do_stop
78 | case "$?" in
79 | 0|1)
80 | do_start
81 | case "$?" in
82 | 0) log_end_msg 0 ;;
83 | 1) log_end_msg 1 ;; # Old process is still running
84 | *) log_end_msg 1 ;; # Failed to start
85 | esac
86 | ;;
87 | *)
88 | # Failed to stop
89 | log_end_msg 1
90 | ;;
91 | esac
92 | ;;
93 | *)
94 | echo "Usage: $SCRIPTNAME {start|stop|restart}" >&2
95 | exit 3
96 | ;;
97 | esac
98 |
99 | :
--------------------------------------------------------------------------------
/resources/init_d/buddycloud-search:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 | # Original /etc/init.d/skeleton modified for http://mydebian.blogdns.org
3 |
4 | # PATH should only include /usr/* if it runs after the mountnfs.sh script
5 | PATH=/sbin:/usr/sbin:/bin:/usr/bin
6 | DESC="Buddycloud channel directory - Search engine"
7 | NAME="channeldirectory-search"
8 | RUNFROM=/opt/buddycloud-channeldirectory
9 | DAEMON=/usr/bin/java
10 | DAEMON_ARGS="-cp .:./*:./lib/* com.buddycloud.channeldirectory.search.Main"
11 | PIDFILE=/var/run/$NAME.pid
12 | SCRIPTNAME=/etc/init.d/buddycloud-search
13 |
14 | # the user that will run the script
15 | USER=buddycloud-channeldir
16 |
17 | # Make sure only root can run our script
18 | if [ "$(id -u)" != "0" ]; then
19 | echo "This script must be run as root. Try using sudo." 1>&2
20 | exit 1
21 | fi
22 |
23 |
24 | # NO NEED TO MODIFY THE LINES BELOW
25 |
26 | # Load the VERBOSE setting and other rcS variables
27 | . /lib/init/vars.sh
28 |
29 | # Define LSB log_* functions.
30 | # Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
31 | . /lib/lsb/init-functions
32 |
33 | #
34 | # Function that starts the daemon/service
35 | #
36 | do_start()
37 | {
38 |
39 | start-stop-daemon -b --start --quiet --chuid $USER --chdir $RUNFROM -m -p $PIDFILE --exec $DAEMON -- $DAEMON_ARGS \
40 | || return 2
41 | }
42 |
43 | #
44 | # Function that stops the daemon/service
45 | #
46 | do_stop()
47 | {
48 | start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE
49 | RETVAL="$?"
50 | rm -f $PIDFILE
51 | return "$RETVAL"
52 | }
53 |
54 | case "$1" in
55 | start)
56 | [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
57 | do_start
58 | case "$?" in
59 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
60 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
61 | esac
62 | ;;
63 | stop)
64 | [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
65 | do_stop
66 | case "$?" in
67 | 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
68 | 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
69 | esac
70 | ;;
71 | restart)
72 | #
73 | # If the "reload" option is implemented then remove the
74 | # 'force-reload' alias
75 | #
76 | log_daemon_msg "Restarting $DESC" "$NAME"
77 | do_stop
78 | case "$?" in
79 | 0|1)
80 | do_start
81 | case "$?" in
82 | 0) log_end_msg 0 ;;
83 | 1) log_end_msg 1 ;; # Old process is still running
84 | *) log_end_msg 1 ;; # Failed to start
85 | esac
86 | ;;
87 | *)
88 | # Failed to stop
89 | log_end_msg 1
90 | ;;
91 | esac
92 | ;;
93 | *)
94 | echo "Usage: $SCRIPTNAME {start|stop|restart}" >&2
95 | exit 3
96 | ;;
97 | esac
98 |
99 | :
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/commons/db/CreateSchema.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.commons.db;
17 |
18 | import java.beans.PropertyVetoException;
19 | import java.io.FileInputStream;
20 | import java.io.FileNotFoundException;
21 | import java.io.IOException;
22 | import java.sql.Connection;
23 | import java.sql.SQLException;
24 | import java.sql.Statement;
25 | import java.util.List;
26 |
27 | import org.apache.commons.io.IOUtils;
28 |
29 | import com.buddycloud.channeldirectory.commons.ConfigurationUtils;
30 |
31 | /**
32 | * Creates jdbc schema required by the crawler
33 | * and by the search engine.
34 | *
35 | */
36 | public class CreateSchema {
37 |
38 | /**
39 | *
40 | */
41 | private static final String SQL_DELIMITER = ";";
42 |
43 | private static final String SQL_CREATE_FILE = ConfigurationUtils.getChannelDirHome()
44 | + "/resources/schema/create-schema.sql";
45 |
46 | @SuppressWarnings("unchecked")
47 | public static void main(String[] args) throws PropertyVetoException, IOException, SQLException {
48 | ChannelDirectoryDataSource channelDirectoryDataSource = new ChannelDirectoryDataSource(
49 | ConfigurationUtils.loadConfiguration());
50 |
51 | runScript(channelDirectoryDataSource, SQL_CREATE_FILE);
52 |
53 | }
54 |
55 | private static void runScript(
56 | ChannelDirectoryDataSource channelDirectoryDataSource, String sqlFile)
57 | throws IOException, FileNotFoundException, SQLException {
58 | List readLines = IOUtils.readLines(
59 | new FileInputStream(sqlFile));
60 |
61 | Connection connection = channelDirectoryDataSource.getConnection();
62 | StringBuilder statementStr = new StringBuilder();
63 |
64 | for (String line : readLines) {
65 | statementStr.append(line);
66 | if (line.endsWith(SQL_DELIMITER)) {
67 | Statement statement = connection.createStatement();
68 | statement.execute(statementStr.toString());
69 | statement.close();
70 | statementStr.setLength(0);
71 | }
72 | }
73 |
74 | connection.close();
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/handler/response/ChannelData.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.handler.response;
17 |
18 | import java.util.Date;
19 |
20 |
21 | /**
22 | * Represents a XMPP channel (identified by its jid)
23 | * with a title and a geolocation attribute.
24 | *
25 | * @see Geolocation
26 | *
27 | */
28 | public class ChannelData extends ContentData {
29 |
30 | /**
31 | * Type constant for channels.
32 | */
33 | private static final String TYPE_CHANNEL = "channel";
34 |
35 | public static final String CH_TYPE_TOPIC = "topic";
36 | public static final String CH_TYPE_PERSONAL = "personal";
37 |
38 | public ChannelData() {
39 | setType(TYPE_CHANNEL);
40 | }
41 |
42 | private String title;
43 | private Geolocation geolocation;
44 | private String channelType;
45 | private String description;
46 | private Date creationDate;
47 |
48 | private String defaultAffiliation;
49 |
50 | public void setGeolocation(Geolocation geolocation) {
51 | this.geolocation = geolocation;
52 | }
53 |
54 | public Geolocation getGeolocation() {
55 | return geolocation;
56 | }
57 |
58 | public void setTitle(String title) {
59 | this.title = title;
60 | }
61 |
62 | public String getTitle() {
63 | return title;
64 | }
65 |
66 | public void setChannelType(String channelType) {
67 | this.channelType = channelType;
68 | }
69 |
70 | public String getChannelType() {
71 | return channelType;
72 | }
73 |
74 | public void setDescription(String description) {
75 | this.description = description;
76 | }
77 |
78 | public String getDescription() {
79 | return description;
80 | }
81 |
82 | public Date getCreationDate() {
83 | return creationDate;
84 | }
85 |
86 | public void setCreationDate(Date creationDate) {
87 | this.creationDate = creationDate;
88 | }
89 |
90 | public void setDefaultAffiliation(String defaultAffiliation) {
91 | this.defaultAffiliation = defaultAffiliation;
92 | }
93 |
94 | public String getDefaultAffiliation() {
95 | return defaultAffiliation;
96 | }
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/Main.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search;
17 |
18 | import java.io.IOException;
19 | import java.util.Properties;
20 |
21 | import org.apache.log4j.Logger;
22 | import org.jivesoftware.whack.ExternalComponentManager;
23 | import org.xmpp.component.ComponentException;
24 |
25 | import com.buddycloud.channeldirectory.commons.ConfigurationUtils;
26 |
27 | /**
28 | * Creates and starts the Channel Directory XMPP component.
29 | * It is also responsible for loading its properties and starting
30 | * the ComponentManager, that abstracts the XMPP connection.
31 | */
32 | public class Main {
33 |
34 | private static Logger LOGGER = Logger.getLogger(Main.class);
35 |
36 | /**
37 | * Starts the server
38 | * @param args
39 | * @throws IOException
40 | * @throws InterruptedException
41 | */
42 | public static void main(String[] args) throws IOException {
43 |
44 | Properties configuration = ConfigurationUtils.loadConfiguration();
45 |
46 | ExternalComponentManager componentManager = new ExternalComponentManager(
47 | configuration.getProperty("xmpp.host"),
48 | Integer.valueOf(configuration.getProperty("xmpp.port")));
49 |
50 | String subdomain = configuration.getProperty("xmpp.subdomain");
51 | componentManager.setSecretKey(subdomain,
52 | configuration.getProperty("xmpp.secretkey"));
53 |
54 | int currentTry = 1;
55 |
56 | while (true) {
57 | try {
58 | componentManager.addComponent(subdomain,
59 | new ChannelDirectoryComponent(configuration));
60 | break;
61 | } catch (ComponentException e) {
62 | LOGGER.warn("Component could not be started. Try #" + (currentTry++));
63 | try {
64 | Thread.sleep(5000);
65 | } catch (InterruptedException e1) {
66 | LOGGER.fatal("Main loop.", e1);
67 | return;
68 | }
69 | }
70 | }
71 |
72 | LOGGER.debug("Component successfully started.");
73 |
74 | while (true) {
75 | try {
76 | Thread.sleep(10000);
77 | } catch (InterruptedException e) {
78 | LOGGER.fatal("Main loop.", e);
79 | }
80 | }
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/rsm/MahoutRSMUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.rsm;
17 |
18 | import java.util.List;
19 |
20 | import com.buddycloud.channeldirectory.search.handler.common.mahout.RecommendationResponse;
21 | import com.buddycloud.channeldirectory.search.handler.response.ChannelData;
22 |
23 | /**
24 | * It is responsible for providing utility methods related to RSM format
25 | * (http://xmpp.org/extensions/xep-0059.html),
26 | * which are used on the Solr query processing and response.
27 | *
28 | * @see RSM
29 | *
30 | */
31 | public class MahoutRSMUtils {
32 |
33 | public static int preprocess(RSM rsm)
34 | throws IllegalArgumentException {
35 |
36 | String after = rsm.getAfter();
37 | String before = rsm.getBefore();
38 |
39 | int initialIndex = rsm.getIndex();
40 | int lastIndex = -1;
41 |
42 | if (after != null) {
43 | initialIndex = Integer.valueOf(after);
44 | }
45 | if (before != null && !before.isEmpty()) {
46 | lastIndex = Integer.valueOf(before) - 2;
47 | }
48 |
49 | if (rsm.getMax() != null) {
50 | if (before != null) {
51 | initialIndex = lastIndex - rsm.getMax() + 1;
52 | } else {
53 | lastIndex = initialIndex + rsm.getMax() - 1;
54 | }
55 | }
56 |
57 | rsm.setIndex(initialIndex);
58 | rsm.setFirst(String.valueOf(initialIndex + 1));
59 | rsm.setLast(String.valueOf(lastIndex + 1));
60 |
61 | return lastIndex + 1;
62 | }
63 |
64 | public static List postprocess(
65 | RecommendationResponse response, RSM rsm)
66 | throws IllegalArgumentException {
67 |
68 | rsm.setCount(response.getNumFound());
69 | List allItems = response.getResponse();
70 |
71 | Integer fromIndex = Integer.valueOf(rsm.getFirst()) - 1;
72 | Integer toIndex = Math.min(Integer.valueOf(rsm.getLast()), allItems.size());
73 |
74 | List responseItems = allItems.subList(fromIndex, toIndex);
75 |
76 | if (responseItems.isEmpty()) {
77 | rsm.setFirst(null);
78 | rsm.setLast(null);
79 | } else {
80 | rsm.setLast(toIndex.toString());
81 | }
82 |
83 | return responseItems;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/main/java/org/jivesoftware/smackx/pubsub/BuddycloudNode.java:
--------------------------------------------------------------------------------
1 | package org.jivesoftware.smackx.pubsub;
2 |
3 | import java.util.Collection;
4 | import java.util.LinkedList;
5 | import java.util.List;
6 |
7 | import org.jivesoftware.smack.SmackException.NoResponseException;
8 | import org.jivesoftware.smack.SmackException.NotConnectedException;
9 | import org.jivesoftware.smack.XMPPException.XMPPErrorException;
10 | import org.jivesoftware.smack.packet.IQ.Type;
11 | import org.jivesoftware.smack.packet.PacketExtension;
12 | import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
13 | import org.jivesoftware.smackx.pubsub.packet.PubSub;
14 | import org.jivesoftware.smackx.pubsub.packet.PubSubNamespace;
15 |
16 | public class BuddycloudNode {
17 |
18 | private final Node node;
19 |
20 | public BuddycloudNode(Node node) {
21 | this.node = node;
22 | }
23 |
24 | public List getBuddycloudAffiliations(List additionalExtensions,
25 | Collection returnedExtensions) throws NoResponseException, XMPPErrorException,
26 | NotConnectedException {
27 |
28 | PubSub pubSub = node.createPubsubPacket(Type.get, new NodeExtension(
29 | PubSubElementType.AFFILIATIONS, node.getId()));
30 | if (additionalExtensions != null) {
31 | for (PacketExtension pe : additionalExtensions) {
32 | pubSub.addExtension(pe);
33 | }
34 | }
35 | PubSub reply = (PubSub) node.sendPubsubPacket(pubSub);
36 | if (returnedExtensions != null) {
37 | returnedExtensions.addAll(reply.getExtensions());
38 | }
39 | BuddycloudAffiliations affilElem = (BuddycloudAffiliations) reply
40 | .getExtension(BuddycloudAffiliations.ELEMENT_NAME, PubSubNamespace.OWNER.getXmlns());
41 | return affilElem.getAffiliations();
42 | }
43 |
44 | public String getId() {
45 | return node.getId();
46 | }
47 |
48 | public DiscoverInfo discoverInfo() throws NoResponseException, XMPPErrorException, NotConnectedException {
49 | return node.discoverInfo();
50 | }
51 |
52 | @SuppressWarnings("unchecked")
53 | public List- getItems(List additionalExtensions,
54 | List returnedExtensions) throws NoResponseException, XMPPErrorException, NotConnectedException {
55 | PubSub request = node.createPubsubPacket(Type.get, new GetItemsRequest(getId()));
56 | if (additionalExtensions != null) {
57 | for (PacketExtension pe : additionalExtensions) {
58 | request.addExtension(pe);
59 | }
60 | }
61 | PubSub result = (PubSub) node.con.createPacketCollectorAndSend(request)
62 | .nextResultOrThrow();
63 | if (returnedExtensions != null) {
64 | returnedExtensions.addAll(result.getExtensions());
65 | }
66 | ItemsExtension itemsElem = (ItemsExtension) result
67 | .getExtension(PubSubElementType.ITEMS);
68 | if (itemsElem == null) {
69 | return new LinkedList
- ();
70 | }
71 | return (List
- ) itemsElem.getItems();
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/commons/db/ChannelDirectoryDataSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.commons.db;
17 |
18 | import java.beans.PropertyVetoException;
19 | import java.sql.Connection;
20 | import java.sql.PreparedStatement;
21 | import java.sql.SQLException;
22 | import java.sql.Statement;
23 | import java.util.Properties;
24 |
25 | import com.mchange.v2.c3p0.ComboPooledDataSource;
26 |
27 | /**
28 | * Handles requests related to the PostgreSQL data source,
29 | * that stores crawled nodes and their update times.
30 | * It uses a {@link ComboPooledDataSource} to improve connection
31 | * pooling.
32 | *
33 | */
34 | public class ChannelDirectoryDataSource {
35 |
36 | private ComboPooledDataSource dataSource;
37 | private Properties configuration;
38 |
39 | public ChannelDirectoryDataSource(Properties configuration) throws PropertyVetoException {
40 | this.configuration = configuration;
41 | createDataSource();
42 | }
43 |
44 | public Statement createStatement() throws SQLException {
45 | return dataSource.getConnection().createStatement();
46 | }
47 |
48 | public PreparedStatement prepareStatement(String statement, Object... args) throws SQLException {
49 | PreparedStatement prepareStatement = dataSource.getConnection().prepareStatement(statement);
50 | for (int i = 1; i <= args.length; i++) {
51 | prepareStatement.setObject(i, args[i-1]);
52 | }
53 | return prepareStatement;
54 | }
55 |
56 | public static void close(Statement statement) {
57 |
58 | if (statement == null) {
59 | return;
60 | }
61 |
62 | try {
63 | Connection connection = statement.getConnection();
64 | statement.close();
65 | connection.close();
66 | } catch (SQLException e) {
67 | e.printStackTrace();
68 | }
69 | }
70 |
71 | public Connection getConnection() throws SQLException {
72 | return dataSource.getConnection();
73 | }
74 |
75 | private void createDataSource() throws PropertyVetoException {
76 | this.dataSource = new ComboPooledDataSource();
77 | dataSource.setInitialPoolSize(5);
78 | dataSource.setMinPoolSize(5);
79 | dataSource.setMaxPoolSize(10);
80 | dataSource.setDriverClass(configuration.getProperty("mahout.jdbc.driver",
81 | "org.postgresql.Driver"));
82 | dataSource.setJdbcUrl(configuration.getProperty("mahout.jdbc.url"));
83 | }
84 |
85 | /**
86 | * @return the dataSource
87 | */
88 | public ComboPooledDataSource getDataSource() {
89 | return dataSource;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/crawler/Main.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.crawler;
17 |
18 | import java.net.MalformedURLException;
19 | import java.util.Properties;
20 |
21 | import org.apache.log4j.Logger;
22 | import org.jivesoftware.smack.PacketListener;
23 | import org.jivesoftware.smack.XMPPConnection;
24 | import org.jivesoftware.smack.XMPPException;
25 | import org.jivesoftware.smack.filter.PacketFilter;
26 | import org.jivesoftware.smack.packet.IQ;
27 | import org.jivesoftware.smack.packet.Packet;
28 |
29 | import com.buddycloud.channeldirectory.commons.ConfigurationUtils;
30 | import com.buddycloud.channeldirectory.commons.db.ChannelDirectoryDataSource;
31 | import com.buddycloud.channeldirectory.crawler.node.NodeCrawler;
32 | import com.buddycloud.channeldirectory.search.utils.XMPPUtils;
33 |
34 | /**
35 | * Creates and starts the Crawler component.
36 | *
37 | */
38 | public class Main {
39 |
40 | private static Logger LOGGER = Logger.getLogger(Main.class);
41 |
42 | /**
43 | * Starts the crawler. This methods create several {@link NodeCrawler}
44 | * for each crawling subject.
45 | *
46 | * @param args
47 | * @throws MalformedURLException
48 | * @throws XMPPException
49 | * @throws InterruptedException
50 | */
51 | public static void main(String[] args) throws Exception {
52 |
53 | Properties configuration = ConfigurationUtils.loadConfiguration();
54 | XMPPConnection connection = XMPPUtils.createCrawlerConnection(configuration);
55 | addTraceListeners(connection);
56 |
57 | PubSubManagers managers = new PubSubManagers(connection);
58 | ChannelDirectoryDataSource dataSource = new ChannelDirectoryDataSource(configuration);
59 |
60 | PubSubSubscriptionListener listener = new PubSubSubscriptionListener(
61 | configuration, managers, dataSource);
62 |
63 | new PubSubServerCrawler(configuration, managers,
64 | dataSource, connection, listener).start();
65 | }
66 |
67 | private static void addTraceListeners(XMPPConnection connection) {
68 | PacketFilter iqFilter = new PacketFilter() {
69 | @Override
70 | public boolean accept(Packet arg0) {
71 | return arg0 instanceof IQ;
72 | }
73 | };
74 |
75 | connection.addPacketSendingListener(new PacketListener() {
76 | @Override
77 | public void processPacket(Packet arg0) {
78 | LOGGER.debug("S: " + arg0.toXML());
79 | }
80 | }, iqFilter);
81 |
82 | connection.addPacketListener(new PacketListener() {
83 |
84 | @Override
85 | public void processPacket(Packet arg0) {
86 | LOGGER.debug("R: " + arg0.toXML());
87 | }
88 | }, iqFilter);
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/handler/response/PostData.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.handler.response;
17 |
18 | import java.util.Date;
19 |
20 | import com.buddycloud.channeldirectory.search.handler.common.PostQueryHandler;
21 |
22 | /**
23 | * Represents a response data for searches
24 | * to posts.
25 | *
26 | * @see PostQueryHandler
27 | *
28 | */
29 | public class PostData extends ContentData {
30 |
31 | private Geolocation geolocation;
32 |
33 | private String author;
34 | private String authorUri;
35 |
36 | private String content;
37 |
38 | private String serverId;
39 |
40 | private String inReplyTo;
41 |
42 | private Date updated;
43 | private Date published;
44 |
45 | private String parentSimpleId;
46 | private String parentFullId;
47 |
48 | public String getAuthor() {
49 | return author;
50 | }
51 |
52 | public void setAuthor(String author) {
53 | this.author = author;
54 | }
55 |
56 | public String getContent() {
57 | return content;
58 | }
59 |
60 | public void setContent(String content) {
61 | this.content = content;
62 | }
63 |
64 | public String getInReplyTo() {
65 | return inReplyTo;
66 | }
67 |
68 | public void setInReplyTo(String inReplyTo) {
69 | this.inReplyTo = inReplyTo;
70 | }
71 |
72 | public Date getUpdated() {
73 | return updated;
74 | }
75 |
76 | public void setUpdated(Date updated) {
77 | this.updated = updated;
78 | }
79 |
80 | public void setGeolocation(Geolocation geolocation) {
81 | this.geolocation = geolocation;
82 | }
83 |
84 | public Geolocation getGeolocation() {
85 | return geolocation;
86 | }
87 |
88 | public void setServerId(String serverId) {
89 | this.serverId = serverId;
90 | }
91 |
92 | public String getServerId() {
93 | return serverId;
94 | }
95 |
96 | /**
97 | * @param authorUri
98 | */
99 | public void setAuthorURI(String authorUri) {
100 | this.authorUri = authorUri;
101 | }
102 |
103 | /**
104 | * @return the authorUri
105 | */
106 | public String getAuthorUri() {
107 | return authorUri;
108 | }
109 |
110 | public Date getPublished() {
111 | return published;
112 | }
113 |
114 | public void setPublished(Date published) {
115 | this.published = published;
116 | }
117 |
118 | public String getParentSimpleId() {
119 | return parentSimpleId;
120 | }
121 |
122 | public void setParentSimpleId(String parentSimpleId) {
123 | this.parentSimpleId = parentSimpleId;
124 | }
125 |
126 | public String getParentFullId() {
127 | return parentFullId;
128 | }
129 |
130 | public void setParentFullId(String parentFullId) {
131 | this.parentFullId = parentFullId;
132 | }
133 |
134 | }
135 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/utils/FeatureUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.utils;
17 |
18 | import java.util.HashSet;
19 | import java.util.List;
20 | import java.util.Set;
21 |
22 | import org.dom4j.Element;
23 |
24 | /**
25 | * Utility methods for options filtering.
26 | *
27 | */
28 | public class FeatureUtils {
29 |
30 | /**
31 | * Parses options features from an IQ request
32 | * Returns an empty map if there is no tag
33 | *
34 | * @param request
35 | * @return
36 | */
37 | @SuppressWarnings("unchecked")
38 | public static Set parseOptions(Element queryElement) {
39 | Element optionsElement = queryElement.element("options");
40 | Set options = new HashSet();
41 |
42 | if (optionsElement == null) {
43 | return options;
44 | }
45 |
46 | List features = optionsElement.elements("feature");
47 | for (Element element : features) {
48 | options.add(element.attributeValue("var"));
49 | }
50 |
51 | return options;
52 | }
53 |
54 | /**
55 | * Adds an attribute to the parent element if the corresponding
56 | * feature is contained in the options map or this map is empty.
57 | *
58 | * @param options
59 | * @param parentElement
60 | * @param key
61 | * @param value
62 | * @return
63 | */
64 | public static boolean addAttribute(Set options,
65 | Element parentElement, String key, String value) {
66 | if (options.contains(key) || options.isEmpty()) {
67 | parentElement.addAttribute(key, value);
68 | return true;
69 | }
70 | return false;
71 | }
72 |
73 | /**
74 | * Adds an element to the parent element and set its text
75 | * if the corresponding feature is contained in the options map
76 | * or this map is empty.
77 | *
78 | * @param options
79 | * @param parentElement
80 | * @param key
81 | * @param value
82 | * @return
83 | */
84 | public static Element addElement(Set options,
85 | Element parentElement, String key, String value) {
86 | if (options.contains(key) || options.isEmpty()) {
87 | Element el = parentElement.addElement(key);
88 | if (value != null) {
89 | el.setText(value);
90 | }
91 | return el;
92 | }
93 | return null;
94 | }
95 |
96 | /**
97 | * Adds an element to the parent element and set its namespace
98 | * if the corresponding feature is contained in the options map
99 | * or this map is empty.
100 | *
101 | * @param options
102 | * @param parentElement
103 | * @param key
104 | * @param namespace
105 | * @return
106 | */
107 | public static Element addNamespaceElement(Set options,
108 | Element parentElement, String key, String namespace) {
109 | if (options.contains(key) || options.isEmpty()) {
110 | return parentElement.addElement(key, namespace);
111 | }
112 | return null;
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/crawler/node/DiscoveryUtils.java:
--------------------------------------------------------------------------------
1 | package com.buddycloud.channeldirectory.crawler.node;
2 |
3 | import java.util.List;
4 |
5 | import org.apache.log4j.Logger;
6 | import org.jivesoftware.smack.XMPPConnection;
7 | import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
8 | import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
9 | import org.jivesoftware.smackx.disco.packet.DiscoverItems;
10 | import org.jivesoftware.smackx.pubsub.PubSubManager;
11 | import org.xbill.DNS.Lookup;
12 | import org.xbill.DNS.Name;
13 | import org.xbill.DNS.Record;
14 | import org.xbill.DNS.SRVRecord;
15 | import org.xbill.DNS.TextParseException;
16 | import org.xbill.DNS.Type;
17 |
18 | public class DiscoveryUtils {
19 |
20 | private static Logger LOGGER = Logger.getLogger(DiscoveryUtils.class);
21 |
22 | private static final String IDENTITY_CATEGORY = "pubsub";
23 | private static final String IDENTITY_TYPE = "channels";
24 | private static final String SRV_PREFIX = "_buddycloud-server._tcp.";
25 |
26 | public static String discoverChannelServer(XMPPConnection connection, String domain) {
27 | try {
28 | String channelServer = doDNSDiscovery(domain);
29 | if (channelServer != null) {
30 | return channelServer;
31 | }
32 | } catch (Exception e) {
33 | LOGGER.warn("No SRV records for " + domain + ", trying XMPP disco.");
34 | }
35 |
36 | try {
37 | return doXMPPDiscovery(connection, domain);
38 | } catch (Exception e) {
39 | LOGGER.warn("No XMPP disco entries for " + domain + ", giving up.");
40 | return null;
41 | }
42 | }
43 |
44 | private static String doDNSDiscovery(String domain) throws TextParseException {
45 | Lookup lookup = new Lookup(SRV_PREFIX + domain, Type.SRV);
46 | Record recs[] = lookup.run();
47 | if (recs == null) {
48 | throw new RuntimeException("Could not lookup domain.");
49 | }
50 |
51 | for (Record rec : recs) {
52 | SRVRecord record = (SRVRecord) rec;
53 | Name target = record.getTarget();
54 | if (target != null) {
55 | String targetStr = target.toString();
56 | return targetStr.substring(0, targetStr.length() - 1);
57 | }
58 | }
59 | return null;
60 | }
61 |
62 | private static String doXMPPDiscovery(XMPPConnection connection,
63 | String domain) {
64 | ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(connection);
65 | PubSubManager pubSubManager = new PubSubManager(connection, domain);
66 |
67 | DiscoverItems discoverItems = null;
68 | try {
69 | discoverItems = pubSubManager.discoverNodes(null);
70 | } catch (Exception e) {
71 | LOGGER.error("Error while trying to fetch domain " + domain
72 | + "node", e);
73 | return null;
74 | }
75 | List items = discoverItems.getItems();
76 | for (DiscoverItems.Item item : items) {
77 | String entityID = item.getEntityID();
78 | DiscoverInfo discoverInfo = null;
79 | try {
80 | discoverInfo = discoManager.discoverInfo(entityID);
81 | } catch (Exception e) {
82 | continue;
83 | }
84 | List identities = discoverInfo
85 | .getIdentities();
86 | for (DiscoverInfo.Identity identity : identities) {
87 | if (isChannelServerIdentity(identity)) {
88 | return entityID;
89 | }
90 | }
91 | }
92 | return null;
93 | }
94 |
95 | private static boolean isChannelServerIdentity(DiscoverInfo.Identity identity) {
96 | return identity.getCategory().equals(IDENTITY_CATEGORY) && identity.getType().equals(IDENTITY_TYPE);
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/crawler/node/FirehoseCrawler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.crawler.node;
17 |
18 | import java.util.HashSet;
19 | import java.util.LinkedList;
20 | import java.util.List;
21 | import java.util.Properties;
22 | import java.util.Set;
23 |
24 | import org.apache.log4j.Logger;
25 | import org.dom4j.Element;
26 | import org.jivesoftware.smack.packet.PacketExtension;
27 | import org.jivesoftware.smackx.pubsub.BuddycloudNode;
28 | import org.jivesoftware.smackx.pubsub.Item;
29 | import org.jivesoftware.smackx.pubsub.Node;
30 | import org.jivesoftware.smackx.rsm.packet.RSMSet;
31 |
32 | import com.buddycloud.channeldirectory.commons.db.ChannelDirectoryDataSource;
33 |
34 | /**
35 | * Responsible for crawling {@link Node} data
36 | * regarding its posts.
37 | *
38 | */
39 | public class FirehoseCrawler implements NodeCrawler {
40 |
41 | /**
42 | *
43 | */
44 | private static Logger LOGGER = Logger.getLogger(FirehoseCrawler.class);
45 |
46 | private final ChannelDirectoryDataSource dataSource;
47 | private PostCrawler postCrawler;
48 |
49 | public FirehoseCrawler(Properties configuration, ChannelDirectoryDataSource dataSource) {
50 | this.dataSource = dataSource;
51 | this.postCrawler = new PostCrawler(configuration, dataSource);
52 | }
53 |
54 | /* (non-Javadoc)
55 | * @see com.buddycloud.channeldirectory.crawler.node.NodeCrawler#crawl(org.jivesoftware.smackx.pubsub.Node)
56 | */
57 | @Override
58 | public void crawl(BuddycloudNode node, String server) throws Exception {
59 |
60 | String newerThan = CrawlerHelper.getLastItemCrawled(server, dataSource);
61 | String olderItemId = null;
62 |
63 | Set nodesAlreadyVisited = new HashSet();
64 |
65 | while (true) {
66 | List additionalExtensions = new LinkedList();
67 | List returnedExtensions = new LinkedList();
68 | List
- items = null;
69 | if (olderItemId != null) {
70 | RSMSet nextRsmSet = RSMSet.newAfter(olderItemId);
71 | additionalExtensions.add(nextRsmSet);
72 | }
73 | items = node.getItems(additionalExtensions, returnedExtensions);
74 | if (items.isEmpty()) {
75 | break;
76 | }
77 | boolean done = false;
78 | for (Item item : items) {
79 | Element itemEntry = CrawlerHelper.getAtomEntry(item);
80 | String itemId = itemEntry.elementText("id");
81 | if (newerThan != null && itemId.equals(newerThan)) {
82 | done = true;
83 | break;
84 | }
85 | olderItemId = itemId;
86 | try {
87 | String nodeId = CrawlerHelper.getNodeFromItemId(itemId);
88 | postCrawler.processPost(nodeId,
89 | CrawlerHelper.getChannelFromNode(nodeId), item);
90 | if (nodesAlreadyVisited.add(nodeId)) {
91 | CrawlerHelper.updateLastItemCrawled(node,
92 | itemId, server, dataSource);
93 | }
94 | } catch (Exception e) {
95 | LOGGER.warn(e);
96 | }
97 | }
98 | if (done) {
99 | break;
100 | }
101 | }
102 | }
103 |
104 |
105 | /* (non-Javadoc)
106 | * @see com.buddycloud.channeldirectory.crawler.node.NodeCrawler#accept(org.jivesoftware.smackx.pubsub.Node)
107 | */
108 | @Override
109 | public boolean accept(BuddycloudNode node) {
110 | return node.getId().equals("/firehose");
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/handler/recommendation/RecommendationQueryHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.handler.recommendation;
17 |
18 | import java.sql.SQLException;
19 | import java.util.List;
20 | import java.util.Properties;
21 |
22 | import org.apache.mahout.cf.taste.common.TasteException;
23 | import org.dom4j.Element;
24 | import org.xmpp.packet.IQ;
25 |
26 | import com.buddycloud.channeldirectory.search.handler.common.ChannelQueryHandler;
27 | import com.buddycloud.channeldirectory.search.handler.common.mahout.ChannelRecommender;
28 | import com.buddycloud.channeldirectory.search.handler.common.mahout.RecommendationResponse;
29 | import com.buddycloud.channeldirectory.search.handler.response.ChannelData;
30 | import com.buddycloud.channeldirectory.search.rsm.MahoutRSMUtils;
31 | import com.buddycloud.channeldirectory.search.rsm.RSM;
32 | import com.buddycloud.channeldirectory.search.rsm.RSMUtils;
33 | import com.buddycloud.channeldirectory.search.utils.XMPPUtils;
34 |
35 | /**
36 | * Handles queries for user recommendation.
37 | * A query should contain an user jid, so
38 | * this handler can return recommended channels
39 | * to this given user.
40 | *
41 | */
42 | public class RecommendationQueryHandler extends ChannelQueryHandler {
43 |
44 | private static final int DEFAULT_PAGE = 10;
45 |
46 | private final ChannelRecommender recommender;
47 |
48 | public RecommendationQueryHandler(Properties properties, ChannelRecommender recommender) {
49 | super("http://buddycloud.com/channel_directory/recommendation_query", properties);
50 | this.recommender = recommender;
51 | }
52 |
53 | @Override
54 | public IQ handle(IQ iq) {
55 |
56 | Element queryElement = iq.getElement().element("query");
57 | Element userJidElement = queryElement.element("user-jid");
58 |
59 | if (userJidElement == null) {
60 | return XMPPUtils.error(iq, "Query does not contain user-jid element.",
61 | getLogger());
62 | }
63 |
64 | String userJid = userJidElement.getText();
65 |
66 | if (userJid == null || userJid.isEmpty()) {
67 | return XMPPUtils.error(iq, "User-jid cannot be empty.",
68 | getLogger());
69 | }
70 |
71 | RSM rsm = RSMUtils.parseRSM(queryElement);
72 | rsm.setMax(rsm.getMax() != null ? rsm.getMax() : DEFAULT_PAGE);
73 |
74 | List recommendedChannels;
75 | try {
76 | recommendedChannels = findRecommendedChannels(userJid, rsm);
77 | } catch (Exception e) {
78 | return XMPPUtils.error(iq, "Search could not be performed, service is unavailable.",
79 | e, getLogger());
80 | }
81 |
82 | List recommendedChannelsFullData;
83 | try {
84 | recommendedChannelsFullData = retrieveFromSolr(recommendedChannels);
85 | } catch (Exception e) {
86 | return XMPPUtils.error(iq, "Search could not be performed, service is unavailable.",
87 | e, getLogger());
88 | }
89 |
90 | return createIQResponse(iq, recommendedChannelsFullData, rsm);
91 | }
92 |
93 | private List findRecommendedChannels(String search, RSM rsm)
94 | throws TasteException, SQLException {
95 | int howMany = MahoutRSMUtils.preprocess(rsm);
96 | RecommendationResponse response = recommender.recommend(search, howMany);
97 | return MahoutRSMUtils.postprocess(response, rsm);
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/handler/similarity/SimilarityQueryHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.handler.similarity;
17 |
18 | import java.sql.SQLException;
19 | import java.util.List;
20 | import java.util.Properties;
21 |
22 | import org.apache.mahout.cf.taste.common.TasteException;
23 | import org.dom4j.Element;
24 | import org.xmpp.packet.IQ;
25 |
26 | import com.buddycloud.channeldirectory.search.handler.common.ChannelQueryHandler;
27 | import com.buddycloud.channeldirectory.search.handler.common.mahout.ChannelRecommender;
28 | import com.buddycloud.channeldirectory.search.handler.common.mahout.RecommendationResponse;
29 | import com.buddycloud.channeldirectory.search.handler.response.ChannelData;
30 | import com.buddycloud.channeldirectory.search.rsm.MahoutRSMUtils;
31 | import com.buddycloud.channeldirectory.search.rsm.RSM;
32 | import com.buddycloud.channeldirectory.search.rsm.RSMUtils;
33 | import com.buddycloud.channeldirectory.search.utils.XMPPUtils;
34 |
35 | /**
36 | * Handles queries for user recommendation.
37 | * A query should contain an user jid, so
38 | * this handler can return recommended channels
39 | * to this given user.
40 | *
41 | */
42 | public class SimilarityQueryHandler extends ChannelQueryHandler {
43 |
44 | private static final int DEFAULT_PAGE = 10;
45 | private final ChannelRecommender recommender;
46 |
47 | public SimilarityQueryHandler(Properties properties, ChannelRecommender recommender) {
48 | super("http://buddycloud.com/channel_directory/similar_channels", properties);
49 | this.recommender = recommender;
50 | }
51 |
52 | @Override
53 | public IQ handle(IQ iq) {
54 |
55 | Element queryElement = iq.getElement().element("query");
56 | Element channelJidElement = queryElement.element("channel-jid");
57 |
58 | if (channelJidElement == null) {
59 | return XMPPUtils.error(iq, "Query does not contain channel-jid element.",
60 | getLogger());
61 | }
62 |
63 | String channelJid = channelJidElement.getText();
64 |
65 | if (channelJid == null || channelJid.isEmpty()) {
66 | return XMPPUtils.error(iq, "Channel-jid cannot be empty.",
67 | getLogger());
68 | }
69 |
70 | RSM rsm = RSMUtils.parseRSM(queryElement);
71 | rsm.setMax(rsm.getMax() != null ? rsm.getMax() : DEFAULT_PAGE);
72 |
73 | List similarChannels;
74 | try {
75 | similarChannels = findSimilarChannels(channelJid, rsm);
76 | } catch (Exception e) {
77 | return XMPPUtils.error(iq,
78 | "Search could not be performed, service is unavailable.",
79 | e, getLogger());
80 | }
81 |
82 | List similarChannelsFullData;
83 | try {
84 | similarChannelsFullData = retrieveFromSolr(similarChannels);
85 | } catch (Exception e) {
86 | return XMPPUtils.error(iq, "Search could not be performed, service is unavailable.",
87 | e, getLogger());
88 | }
89 |
90 | return createIQResponse(iq, similarChannelsFullData, rsm);
91 | }
92 |
93 | private List findSimilarChannels(String search, RSM rsm)
94 | throws TasteException, SQLException {
95 | int howMany = MahoutRSMUtils.preprocess(rsm);
96 | RecommendationResponse recommendationResponse = recommender.getSimilarChannels(search, howMany);
97 | return MahoutRSMUtils.postprocess(recommendationResponse, rsm);
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/handler/metadata/MetadataQueryHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.handler.metadata;
17 |
18 | import java.net.MalformedURLException;
19 | import java.util.ArrayList;
20 | import java.util.List;
21 | import java.util.Properties;
22 |
23 | import org.apache.solr.client.solrj.SolrQuery;
24 | import org.apache.solr.client.solrj.SolrServer;
25 | import org.apache.solr.client.solrj.SolrServerException;
26 | import org.apache.solr.client.solrj.response.QueryResponse;
27 | import org.apache.solr.common.SolrDocument;
28 | import org.apache.solr.common.SolrDocumentList;
29 | import org.dom4j.Element;
30 | import org.xmpp.packet.IQ;
31 |
32 | import com.buddycloud.channeldirectory.commons.solr.SolrServerFactory;
33 | import com.buddycloud.channeldirectory.commons.solr.SolrUtils;
34 | import com.buddycloud.channeldirectory.search.handler.common.ChannelQueryHandler;
35 | import com.buddycloud.channeldirectory.search.handler.response.ChannelData;
36 | import com.buddycloud.channeldirectory.search.rsm.RSM;
37 | import com.buddycloud.channeldirectory.search.rsm.RSMUtils;
38 | import com.buddycloud.channeldirectory.search.rsm.SolrRSMUtils;
39 | import com.buddycloud.channeldirectory.search.utils.XMPPUtils;
40 |
41 | /**
42 | * Handles queries for content metadata.
43 | * A query should contain a metadata query string, so
44 | * this handle can return channels related to this search.
45 | *
46 | */
47 | public class MetadataQueryHandler extends ChannelQueryHandler {
48 |
49 | public MetadataQueryHandler(Properties properties) {
50 | super("http://buddycloud.com/channel_directory/metadata_query", properties);
51 | }
52 |
53 | @Override
54 | public IQ handle(IQ iq) {
55 |
56 | Element queryElement = iq.getElement().element("query");
57 | Element searchElement = queryElement.element("search");
58 |
59 |
60 | if (searchElement == null) {
61 | return XMPPUtils.error(iq, "Query does not contain search element.",
62 | getLogger());
63 | }
64 |
65 | String search = searchElement.getText();
66 |
67 | if (search == null || search.isEmpty()) {
68 | return XMPPUtils.error(iq, "Search content cannot be empty.",
69 | getLogger());
70 | }
71 |
72 | RSM rsm = RSMUtils.parseRSM(queryElement);
73 |
74 | List channelObjects;
75 | try {
76 | channelObjects = findObjectsByMetadata(rsm, search);
77 | } catch (Exception e) {
78 | return XMPPUtils.error(iq, "Search could not be performed, service is unavailable.",
79 | getLogger());
80 | }
81 |
82 | return createIQResponse(iq, channelObjects, rsm);
83 | }
84 |
85 | private List findObjectsByMetadata(RSM rsm, String search) throws MalformedURLException, SolrServerException {
86 | SolrServer solrServer = new SolrServerFactory().createChannelCore(getProperties());
87 | SolrQuery solrQuery = new SolrQuery(search);
88 |
89 | SolrRSMUtils.preprocess(solrQuery, rsm);
90 | QueryResponse queryResponse = solrServer.query(solrQuery);
91 | SolrRSMUtils.postprocess(queryResponse, rsm);
92 |
93 | return convertResponse(queryResponse);
94 | }
95 |
96 | private static List convertResponse(QueryResponse queryResponse) {
97 | List channels = new ArrayList();
98 | SolrDocumentList results = queryResponse.getResults();
99 |
100 | for (SolrDocument solrDocument : results) {
101 | channels.add(SolrUtils.convertToChannelData(solrDocument));
102 | }
103 |
104 | return channels;
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/crawler/PubSubSubscriptionListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.crawler;
17 |
18 | import java.sql.SQLException;
19 | import java.util.List;
20 | import java.util.Properties;
21 |
22 | import org.apache.log4j.Logger;
23 | import org.jivesoftware.smack.XMPPException;
24 | import org.jivesoftware.smackx.pubsub.ConfigurationEvent;
25 | import org.jivesoftware.smackx.pubsub.ConfigureForm;
26 | import org.jivesoftware.smackx.pubsub.Item;
27 | import org.jivesoftware.smackx.pubsub.ItemDeleteEvent;
28 | import org.jivesoftware.smackx.pubsub.ItemPublishEvent;
29 | import org.jivesoftware.smackx.pubsub.Node;
30 | import org.jivesoftware.smackx.pubsub.listener.ItemDeleteListener;
31 | import org.jivesoftware.smackx.pubsub.listener.ItemEventListener;
32 | import org.jivesoftware.smackx.pubsub.listener.NodeConfigListener;
33 |
34 | import com.buddycloud.channeldirectory.commons.db.ChannelDirectoryDataSource;
35 |
36 | /**
37 | *
38 | */
39 | public class PubSubSubscriptionListener implements ItemDeleteListener, ItemEventListener
- , NodeConfigListener {
40 |
41 | private static Logger LOGGER = Logger.getLogger(PubSubServerCrawler.class);
42 |
43 | private final PubSubManagers managers;
44 | private final ChannelDirectoryDataSource dataSource;
45 | private String userId;
46 |
47 |
48 | /**
49 | * @param configuration
50 | * @param managers
51 | */
52 | public PubSubSubscriptionListener(Properties configuration,
53 | PubSubManagers managers, ChannelDirectoryDataSource dataSource) {
54 | this.managers = managers;
55 | this.dataSource = dataSource;
56 |
57 | String userName = configuration.getProperty("crawler.xmpp.username");
58 | String serverName = configuration.getProperty("crawler.xmpp.servername");
59 |
60 | this.userId = userName + "@" + serverName;
61 |
62 | }
63 |
64 | /* (non-Javadoc)
65 | * @see org.jivesoftware.smackx.pubsub.listener.NodeConfigListener#handleNodeConfiguration(org.jivesoftware.smackx.pubsub.ConfigurationEvent)
66 | */
67 | @Override
68 | public void handleNodeConfiguration(ConfigurationEvent config) {
69 | ConfigureForm configureForm = config.getConfiguration();
70 | }
71 |
72 | /* (non-Javadoc)
73 | * @see org.jivesoftware.smackx.pubsub.listener.ItemEventListener#handlePublishedItems(org.jivesoftware.smackx.pubsub.ItemPublishEvent)
74 | */
75 | @Override
76 | public void handlePublishedItems(ItemPublishEvent
- itemsEvent) {
77 | List
- items = itemsEvent.getItems();
78 | for (Item item : items) {
79 | String itemId = item.getId();
80 | }
81 | }
82 |
83 | /* (non-Javadoc)
84 | * @see org.jivesoftware.smackx.pubsub.listener.ItemDeleteListener#handleDeletedItems(org.jivesoftware.smackx.pubsub.ItemDeleteEvent)
85 | */
86 | @Override
87 | public void handleDeletedItems(ItemDeleteEvent items) {
88 | // TODO Auto-generated method stub
89 |
90 | }
91 |
92 | /* (non-Javadoc)
93 | * @see org.jivesoftware.smackx.pubsub.listener.ItemDeleteListener#handlePurge()
94 | */
95 | @Override
96 | public void handlePurge() {
97 | // TODO Auto-generated method stub
98 |
99 | }
100 |
101 | /**
102 | * @param node
103 | * @throws XMPPException
104 | * @throws SQLException
105 | */
106 | public void listen(Node node, String server) throws XMPPException, SQLException {
107 |
108 | try {
109 | node.subscribe(userId);
110 | } catch (Exception e) {
111 | LOGGER.warn("Node " + node.getId() + " is already subscribed.");
112 | }
113 | node.addConfigurationListener(this);
114 | node.addItemDeleteListener(this);
115 | node.addItemEventListener(this);
116 | }
117 |
118 | }
119 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/cli/Main.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.cli;
17 |
18 | import java.io.FileReader;
19 | import java.util.Collections;
20 | import java.util.HashMap;
21 | import java.util.LinkedList;
22 | import java.util.Map;
23 | import java.util.Properties;
24 |
25 | import org.apache.commons.cli.CommandLine;
26 | import org.apache.commons.cli.CommandLineParser;
27 | import org.apache.commons.cli.HelpFormatter;
28 | import org.apache.commons.cli.Option;
29 | import org.apache.commons.cli.OptionBuilder;
30 | import org.apache.commons.cli.Options;
31 | import org.apache.commons.cli.ParseException;
32 | import org.apache.commons.cli.PosixParser;
33 |
34 | import com.buddycloud.channeldirectory.commons.ConfigurationUtils;
35 | import com.google.gson.JsonArray;
36 | import com.google.gson.JsonElement;
37 | import com.google.gson.JsonObject;
38 | import com.google.gson.JsonParser;
39 |
40 | /**
41 | * @author Abmar
42 | *
43 | */
44 | public class Main {
45 |
46 | private static final String QUERIES_FILE = ConfigurationUtils.getChannelDirHome()
47 | + "/queries.json";
48 |
49 | @SuppressWarnings("static-access")
50 | public static void main(String[] args) throws Exception {
51 |
52 | JsonElement rootElement = new JsonParser().parse(new FileReader(QUERIES_FILE));
53 | JsonArray rootArray = rootElement.getAsJsonArray();
54 |
55 | Map queries = new HashMap();
56 |
57 | for (int i = 0; i < rootArray.size(); i++) {
58 | JsonObject queryElement = rootArray.get(i).getAsJsonObject();
59 | String queryName = queryElement.get("name").getAsString();
60 | String type = queryElement.get("type").getAsString();
61 |
62 | Query query = null;
63 |
64 | if (type.equals("solr")) {
65 | query = new QueryToSolr(queryElement.get("agg").getAsString(),
66 | queryElement.get("core").getAsString(),
67 | queryElement.get("q").getAsString());
68 | } else if (type.equals("dbms")) {
69 | query = new QueryToDBMS(queryElement.get("q").getAsString());
70 | }
71 |
72 |
73 | queries.put(queryName, query);
74 | }
75 |
76 | LinkedList queriesNames = new LinkedList(queries.keySet());
77 | Collections.sort(queriesNames);
78 |
79 | Options options = new Options();
80 | options.addOption(OptionBuilder.isRequired(true)
81 | .withLongOpt("query")
82 | .hasArg(true)
83 | .withDescription("The name of the query. Possible queries are: " + queriesNames)
84 | .create('q'));
85 |
86 | options.addOption(OptionBuilder.isRequired(false)
87 | .withLongOpt("args")
88 | .hasArg(true)
89 | .withDescription("Arguments for the query")
90 | .create('a'));
91 |
92 | options.addOption(new Option("?", "help", false, "Print this message" ));
93 |
94 | CommandLineParser parser = new PosixParser();
95 | CommandLine cmd = null;
96 |
97 | try {
98 | cmd = parser.parse(options, args);
99 | } catch (ParseException e) {
100 | printHelpAndExit(options);
101 | }
102 |
103 | if (cmd.hasOption("help")) {
104 | printHelpAndExit(options);
105 | }
106 |
107 | String queryName = cmd.getOptionValue("q");
108 | String argsCmd = cmd.getOptionValue("a");
109 |
110 | Properties configuration = ConfigurationUtils.loadConfiguration();
111 |
112 | Query query = queries.get(queryName);
113 | if (query == null) {
114 | printHelpAndExit(options);
115 | }
116 |
117 | System.out.println(query.exec(argsCmd, configuration));
118 |
119 | }
120 |
121 | private static void printHelpAndExit(Options options) {
122 | HelpFormatter formatter = new HelpFormatter();
123 | formatter.printHelp("exec-query", options);
124 | System.exit(0);
125 | }
126 |
127 | }
128 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/handler/common/PostQueryHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.handler.common;
17 |
18 | import java.text.DateFormat;
19 | import java.text.SimpleDateFormat;
20 | import java.util.List;
21 | import java.util.Properties;
22 | import java.util.Set;
23 |
24 | import org.dom4j.Element;
25 | import org.xmpp.packet.IQ;
26 |
27 | import com.buddycloud.channeldirectory.search.handler.AbstractQueryHandler;
28 | import com.buddycloud.channeldirectory.search.handler.QueryHandler;
29 | import com.buddycloud.channeldirectory.search.handler.response.Geolocation;
30 | import com.buddycloud.channeldirectory.search.handler.response.PostData;
31 | import com.buddycloud.channeldirectory.search.rsm.RSM;
32 | import com.buddycloud.channeldirectory.search.rsm.RSMUtils;
33 | import com.buddycloud.channeldirectory.search.utils.FeatureUtils;
34 | import com.buddycloud.channeldirectory.search.utils.GeolocationUtils;
35 |
36 | /**
37 | * Abstract class for {@link QueryHandler} that returns
38 | * PostData.
39 | *
40 | */
41 | public abstract class PostQueryHandler extends AbstractQueryHandler {
42 |
43 | private static final String ATOM_NAMESPACE = "http://www.w3.org/2005/Atom";
44 | private static final String THREAD_NAMESPACE = "http://purl.org/syndication/thread/1.0";
45 |
46 | private static final DateFormat DATE_FORMAT = new SimpleDateFormat(
47 | "yyyy-MM-dd'T'HH:mm:ssZ");
48 |
49 | public PostQueryHandler(String namespace, Properties properties) {
50 | super(namespace, properties);
51 | }
52 |
53 | protected IQ createIQResponse(IQ iq, List allContent, RSM rsm) {
54 | IQ result = IQ.createResultIQ(iq);
55 |
56 | Element queryEl = iq.getElement().element("query");
57 |
58 | Set options = FeatureUtils.parseOptions(queryEl);
59 |
60 | Element queryElement = result.getElement().addElement("query", getNamespace());
61 |
62 | for (PostData postObject : allContent) {
63 | Element itemElement = queryElement.addElement("item");
64 |
65 | FeatureUtils.addAttribute(options, itemElement, "id",
66 | postObject.getId());
67 | FeatureUtils.addAttribute(options, itemElement, "type",
68 | postObject.getType());
69 |
70 | Element entryElement = itemElement.addElement("entry", ATOM_NAMESPACE);
71 |
72 | FeatureUtils.addElement(options, entryElement, "author",
73 | postObject.getAuthor());
74 |
75 | Element contentElement = FeatureUtils.addElement(
76 | options, entryElement, "content",
77 | postObject.getContent());
78 | if (contentElement != null) {
79 | contentElement.addAttribute("type", "text");
80 | }
81 |
82 | if (postObject.getUpdated() != null) {
83 | FeatureUtils.addElement(options, entryElement, "updated",
84 | DATE_FORMAT.format(postObject.getUpdated()));
85 | }
86 |
87 | if (postObject.getPublished() != null) {
88 | FeatureUtils.addElement(options, entryElement, "published",
89 | DATE_FORMAT.format(postObject.getPublished()));
90 | }
91 |
92 | FeatureUtils.addElement(options, entryElement, "parent_fullid",
93 | postObject.getParentFullId());
94 | FeatureUtils.addElement(options, entryElement, "parent_simpleid",
95 | postObject.getParentSimpleId());
96 |
97 | Element geoElement = FeatureUtils.addNamespaceElement(
98 | options, entryElement, "geoloc", Geolocation.NAMESPACE);
99 | GeolocationUtils.appendGeoLocation(geoElement,
100 | postObject.getGeolocation());
101 |
102 | Element inReplyEl = FeatureUtils.addNamespaceElement(
103 | options, entryElement, "in-reply-to", THREAD_NAMESPACE);
104 | if (inReplyEl != null) {
105 | inReplyEl.addAttribute("ref", postObject.getInReplyTo());
106 | }
107 | }
108 |
109 | RSMUtils.appendRSMElement(queryElement, rsm);
110 |
111 | return result;
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/utils/XMPPUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.utils;
17 |
18 | import java.util.Properties;
19 | import java.util.Random;
20 |
21 | import javax.net.ssl.HostnameVerifier;
22 | import javax.net.ssl.SSLSession;
23 |
24 | import org.apache.log4j.Logger;
25 | import org.jivesoftware.smack.ConnectionConfiguration;
26 | import org.jivesoftware.smack.XMPPConnection;
27 | import org.jivesoftware.smack.tcp.XMPPTCPConnection;
28 | import org.jivesoftware.smack.util.TLSUtils;
29 | import org.xmpp.packet.IQ;
30 | import org.xmpp.packet.PacketError;
31 | import org.xmpp.packet.PacketError.Condition;
32 | import org.xmpp.packet.PacketError.Type;
33 |
34 | public class XMPPUtils {
35 |
36 |
37 | private static final int REPLY_TIMEOUT = 10000;
38 |
39 | /**
40 | * Logs the error and returns an IQ error response
41 | *
42 | * @param iq
43 | * @param errorMessage
44 | * @param logger
45 | * @return
46 | */
47 | public static IQ error(IQ iq, String errorMessage, Logger logger) {
48 | logger.error(errorMessage);
49 | return XMPPUtils.createErrorResponse(iq, errorMessage,
50 | Condition.bad_request, Type.modify);
51 | }
52 |
53 | /**
54 | * @param iq
55 | * @param errorMessage
56 | * @param logger
57 | * @return
58 | */
59 | public static IQ error(IQ iq, String errorMessage, Exception e, Logger logger) {
60 | logger.error(errorMessage, e);
61 | return XMPPUtils.createErrorResponse(iq, errorMessage,
62 | Condition.bad_request, Type.modify);
63 | }
64 |
65 | /**
66 | * Logs the RSM page not found error and returns an IQ error response
67 | *
68 | * @param iq
69 | * @param errorMessage
70 | * @param logger
71 | * @return
72 | */
73 | public static IQ errorRSM(IQ iq, Logger logger) {
74 | String rsmMessage = "RSM: Page Not Found";
75 | logger.error(rsmMessage + " " + iq);
76 | return XMPPUtils.createErrorResponse(iq, rsmMessage,
77 | Condition.item_not_found, Type.cancel);
78 | }
79 |
80 | /**
81 | * Creates an error response for a given IQ request.
82 | *
83 | * @param request
84 | * @param message
85 | * @param condition
86 | * @param type
87 | * @return
88 | */
89 | public static IQ createErrorResponse(final IQ request, final String message,
90 | Condition condition, Type type) {
91 | final IQ result = request.createCopy();
92 | result.setID(request.getID());
93 | result.setFrom(request.getTo());
94 | result.setTo(request.getFrom());
95 |
96 | PacketError e = new PacketError(condition, type);
97 | if(message != null) {
98 | e.setText(message);
99 | }
100 | result.setError(e);
101 |
102 | return result;
103 | }
104 |
105 | public static XMPPConnection createCrawlerConnection(Properties configuration)
106 | throws Exception {
107 |
108 | String serviceName = configuration.getProperty("crawler.xmpp.servicename");
109 | String host = configuration.getProperty("crawler.xmpp.host");
110 | String userName = configuration.getProperty("crawler.xmpp.username");
111 |
112 | ConnectionConfiguration cc = new ConnectionConfiguration(
113 | host,
114 | Integer.parseInt(configuration.getProperty("crawler.xmpp.port")),
115 | serviceName);
116 | cc.setReconnectionAllowed(true);
117 | acceptAllHostnames(cc);
118 | TLSUtils.acceptAllCertificates(cc);
119 |
120 | XMPPTCPConnection connection = new XMPPTCPConnection(cc);
121 | connection.setPacketReplyTimeout(REPLY_TIMEOUT);
122 | connection.connect();
123 | connection.login(userName,
124 | configuration.getProperty("crawler.xmpp.password"),
125 | "crawler-" + Math.abs(new Random().nextLong()));
126 |
127 | return connection;
128 | }
129 |
130 | private static void acceptAllHostnames(ConnectionConfiguration cc) {
131 | cc.setHostnameVerifier(new HostnameVerifier() {
132 | @Override
133 | public boolean verify(String hostname, SSLSession session) {
134 | return true;
135 | }
136 | });
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/handler/common/mahout/MemoryRecommenderDataModel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.handler.common.mahout;
17 |
18 | import java.io.FileReader;
19 | import java.io.IOException;
20 | import java.util.HashMap;
21 | import java.util.LinkedList;
22 | import java.util.List;
23 | import java.util.Map;
24 | import java.util.Map.Entry;
25 | import java.util.Properties;
26 |
27 | import org.apache.mahout.cf.taste.impl.common.FastByIDMap;
28 | import org.apache.mahout.cf.taste.impl.model.BooleanPreference;
29 | import org.apache.mahout.cf.taste.impl.model.BooleanUserPreferenceArray;
30 | import org.apache.mahout.cf.taste.impl.model.GenericDataModel;
31 | import org.apache.mahout.cf.taste.model.DataModel;
32 | import org.apache.mahout.cf.taste.model.Preference;
33 | import org.apache.mahout.cf.taste.model.PreferenceArray;
34 |
35 | import au.com.bytecode.opencsv.CSVReader;
36 |
37 | import com.buddycloud.channeldirectory.search.handler.response.ChannelData;
38 |
39 | /**
40 | * Reads a dump from a CSV file and stores all taste
41 | * data in memory. The CSV file path is addressed by the
42 | * "mahout.dumpfile" property. This is a model for testing purposes
43 | * and it is static.
44 | *
45 | */
46 | public class MemoryRecommenderDataModel implements ChannelRecommenderDataModel {
47 |
48 | private Map userToId = new HashMap();
49 | private Map itemToId = new HashMap();
50 |
51 | private Map idToUser = new HashMap();
52 | private Map idToItem = new HashMap();
53 |
54 | private DataModel dataModel;
55 | private Properties properties;
56 |
57 | public MemoryRecommenderDataModel(Properties properties) {
58 | this.properties = properties;
59 | try {
60 | createDataModel();
61 | } catch (IOException e) {
62 | throw new RuntimeException(e);
63 | }
64 | }
65 |
66 | private void createDataModel() throws IOException {
67 | CSVReader reader = new CSVReader(new FileReader(
68 | properties.getProperty("mahout.dumpfile")));
69 | reader.readNext(); // Read header
70 |
71 | Map> preferences = new HashMap>();
72 |
73 | Long userId = -1L;
74 | Long itemId = -1L;
75 |
76 | while (true) {
77 |
78 | String[] nextLine = reader.readNext();
79 | if (nextLine == null) {
80 | break;
81 | }
82 |
83 | String item = nextLine[0];
84 | String title = nextLine[1];
85 | String user = nextLine[2];
86 |
87 | if (!userToId.containsKey(user)) {
88 | userId++;
89 | userToId.put(user, userId);
90 | idToUser.put(userId, user);
91 | }
92 |
93 | if (!itemToId.containsKey(item)) {
94 | itemId++;
95 | ChannelData chData = new ChannelData();
96 | chData.setId(item);
97 | chData.setTitle(title);
98 |
99 | itemToId.put(item, itemId);
100 | idToItem.put(itemId, chData);
101 | }
102 |
103 | Long currentUserId = userToId.get(user);
104 | BooleanPreference booleanPreference = new BooleanPreference(
105 | currentUserId, itemToId.get(item));
106 |
107 | List prefList = preferences.get(currentUserId);
108 |
109 | if (prefList == null) {
110 | prefList = new LinkedList();
111 | preferences.put(currentUserId, prefList);
112 | }
113 |
114 | prefList.add(booleanPreference);
115 | }
116 |
117 | FastByIDMap userData = new FastByIDMap();
118 | for (Entry> entry : preferences.entrySet()) {
119 | userData.put(entry.getKey(), new BooleanUserPreferenceArray(entry.getValue()));
120 | }
121 |
122 | this.dataModel = new GenericDataModel(userData);
123 | }
124 |
125 |
126 | @Override
127 | public DataModel getDataModel() {
128 | return dataModel;
129 | }
130 |
131 | @Override
132 | public Long toUserId(String userJid) {
133 | return userToId.get(userJid);
134 | }
135 |
136 | @Override
137 | public ChannelData toChannelData(long itemID) {
138 | return idToItem.get(itemID);
139 | }
140 |
141 | @Override
142 | public Long toChannelId(String channelJid) {
143 | return itemToId.get(channelJid);
144 | }
145 |
146 | }
147 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/handler/active/MostActiveQueryHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.handler.active;
17 |
18 | import java.sql.PreparedStatement;
19 | import java.sql.ResultSet;
20 | import java.sql.SQLException;
21 | import java.util.LinkedList;
22 | import java.util.List;
23 | import java.util.Properties;
24 |
25 | import org.dom4j.Element;
26 | import org.xmpp.packet.IQ;
27 |
28 | import com.buddycloud.channeldirectory.commons.db.ChannelDirectoryDataSource;
29 | import com.buddycloud.channeldirectory.search.handler.common.ChannelQueryHandler;
30 | import com.buddycloud.channeldirectory.search.handler.response.ChannelData;
31 | import com.buddycloud.channeldirectory.search.rsm.RSM;
32 | import com.buddycloud.channeldirectory.search.rsm.RSMUtils;
33 | import com.buddycloud.channeldirectory.search.utils.XMPPUtils;
34 |
35 | /**
36 | * Handles queries for content metadata.
37 | * A query should contain a metadata query string, so
38 | * this handle can return channels related to this search.
39 | *
40 | */
41 | public class MostActiveQueryHandler extends ChannelQueryHandler {
42 |
43 | /**
44 | *
45 | */
46 | private static final int DEFAULT_PAGE = 10;
47 | private static final int LOOK_BACK = 7; // In days
48 | private final ChannelDirectoryDataSource dataSource;
49 |
50 | public MostActiveQueryHandler(Properties properties, ChannelDirectoryDataSource dataSource) {
51 | super("http://buddycloud.com/channel_directory/most_active", properties);
52 | this.dataSource = dataSource;
53 | }
54 |
55 | @Override
56 | public IQ handle(IQ iq) {
57 |
58 | Element queryElement = iq.getElement().element("query");
59 |
60 | Element domainEl = queryElement.element("domain");
61 | String domain = domainEl == null ? null : domainEl.getText();
62 |
63 | Element periodEl = queryElement.element("period");
64 | int period = periodEl == null ? LOOK_BACK : Integer.parseInt(periodEl.getText());
65 |
66 | RSM rsm = RSMUtils.parseRSM(queryElement);
67 | List mostActiveChannels = null;
68 |
69 | try {
70 | mostActiveChannels = retrieveMostActiveChannels(dataSource, period, domain, rsm);
71 | } catch (SQLException e1) {
72 | return XMPPUtils.error(iq, "Search could not be performed, service is unavailable.",
73 | getLogger());
74 | }
75 |
76 | List mostActiveChannelsFullData;
77 | try {
78 | mostActiveChannelsFullData = retrieveFromSolr(mostActiveChannels);
79 | } catch (Exception e) {
80 | return XMPPUtils.error(iq, "Search could not be performed, service is unavailable.",
81 | getLogger());
82 | }
83 |
84 | return createIQResponse(iq, mostActiveChannelsFullData, rsm);
85 | }
86 |
87 | private static List retrieveMostActiveChannels(
88 | ChannelDirectoryDataSource dataSource,
89 | int period, String domain, RSM rsm) throws SQLException {
90 |
91 | Integer offset = rsm.getIndex() != null ? rsm.getIndex() : 0;
92 | Integer limit = rsm.getMax() != null ? rsm.getMax() : DEFAULT_PAGE;
93 | rsm.setCount(0);
94 |
95 | PreparedStatement statement = null;
96 | try {
97 | statement = dataSource.prepareStatement(
98 | "SELECT channel_jid, count(*) OVER() AS channel_count FROM channel_activity " +
99 | "WHERE updated > now() - ? * interval'1 day' AND channel_jid LIKE ? " +
100 | "ORDER BY summarized_activity DESC " +
101 | "LIMIT ? OFFSET ?",
102 | period, domain == null ? "%" : "%" + domain,
103 | limit, offset);
104 |
105 | ResultSet resultSet = statement.executeQuery();
106 | List channelsData = new LinkedList();
107 | String lastChannelId = null;
108 | while (resultSet.next()) {
109 | String channelJid = resultSet.getString("channel_jid");
110 | if (lastChannelId == null) {
111 | rsm.setFirst(channelJid);
112 | }
113 | lastChannelId = channelJid;
114 | ChannelData channelData = new ChannelData();
115 | channelData.setId(channelJid);
116 | channelsData.add(channelData);
117 |
118 | rsm.setCount(resultSet.getInt("channel_count"));
119 | }
120 | rsm.setLast(lastChannelId);
121 | return channelsData;
122 | } catch (SQLException e1) {
123 | throw e1;
124 | } finally {
125 | ChannelDirectoryDataSource.close(statement);
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/rsm/RSMUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.rsm;
17 |
18 | import java.util.LinkedList;
19 | import java.util.List;
20 |
21 | import org.dom4j.Element;
22 |
23 | import com.buddycloud.channeldirectory.search.handler.response.ContentData;
24 |
25 | /**
26 | * It is responsible for providing utility methods related to RSM format
27 | * (http://xmpp.org/extensions/xep-0059.html),
28 | * which are used on the query processing and response.
29 | *
30 | * @see RSM
31 | *
32 | */
33 | public class RSMUtils {
34 |
35 | /**
36 | * Appends RSM info to query response.
37 | * @param queryElement
38 | * @param rsm
39 | */
40 | public static void appendRSMElement(Element queryElement, RSM rsm) {
41 | Element setElement = queryElement.addElement("set", RSM.NAMESPACE);
42 |
43 | if (rsm.getFirst() != null) {
44 | Element firstElement = setElement.addElement("first");
45 | firstElement.addAttribute("index", rsm.getIndex().toString());
46 | firstElement.setText(rsm.getFirst());
47 | }
48 |
49 | if (rsm.getLast() != null) {
50 | Element lastElement = setElement.addElement("last");
51 | lastElement.setText(rsm.getLast());
52 | }
53 |
54 | setElement.addElement("count").setText(String.valueOf(rsm.getCount()));
55 | }
56 |
57 | /**
58 | * Parses an RSM from a query XML element
59 | * @param queryElement
60 | * @return The parsed RSM object
61 | */
62 | public static RSM parseRSM(Element queryElement) {
63 | RSM rsm = new RSM();
64 |
65 | Element setElement = queryElement.element("set");
66 | if (setElement == null) {
67 | return rsm;
68 | }
69 |
70 | Element after = setElement.element("after");
71 | if (after != null) {
72 | rsm.setAfter(after.getText());
73 | }
74 |
75 | Element before = setElement.element("before");
76 | if (before != null) {
77 | String beforeText = before.getText();
78 | rsm.setBefore(beforeText == null ? "" : beforeText);
79 | }
80 |
81 | Element index = setElement.element("index");
82 | if (index != null) {
83 | rsm.setIndex(Integer.parseInt(index.getText()));
84 | }
85 |
86 | Element max = setElement.element("max");
87 | if (max != null) {
88 | rsm.setMax(Integer.parseInt(max.getText()));
89 | }
90 |
91 | return rsm;
92 | }
93 |
94 | /**
95 | * Filters response objects based on the RSM parameters.
96 | * Updates the RSM object with item count, first and last jid
97 | *
98 | * @param objects
99 | * @param rsm
100 | * @return
101 | * @throws IllegalArgumentException If the item specified by the requesting
102 | * entity via the UID in the or element does not exist
103 | */
104 | public static List filterRSMResponse(
105 | List objects, RSM rsm)
106 | throws IllegalArgumentException {
107 |
108 | String after = rsm.getAfter();
109 | String before = rsm.getBefore();
110 |
111 | int initialIndex = rsm.getIndex();
112 | int lastIndex = objects.size();
113 |
114 | if (after != null || (before != null && !before.isEmpty())) {
115 |
116 | boolean afterItemFound = false;
117 | boolean beforeItemFound = false;
118 |
119 | int i = 0;
120 | for (T object : objects) {
121 | if (after != null && after.equals(object.getId())) {
122 | initialIndex = i + 1;
123 | afterItemFound = true;
124 | }
125 | if (before != null && before.equals(object.getId())) {
126 | lastIndex = i;
127 | beforeItemFound = true;
128 | }
129 | i++;
130 | }
131 |
132 | if (after != null && !afterItemFound) {
133 | throw new IllegalArgumentException();
134 | }
135 |
136 | if (before != null && !before.isEmpty() && !beforeItemFound) {
137 | throw new IllegalArgumentException();
138 | }
139 | }
140 |
141 | if (rsm.getMax() != null) {
142 | if (before != null) {
143 | initialIndex = lastIndex - rsm.getMax();
144 | } else {
145 | lastIndex = initialIndex + rsm.getMax();
146 | }
147 | }
148 |
149 | boolean outOfRange = initialIndex > lastIndex || initialIndex < 0
150 | || lastIndex > objects.size();
151 |
152 | List filteredList = outOfRange ? new LinkedList() : objects
153 | .subList(initialIndex, lastIndex);
154 |
155 | rsm.setCount(objects.size());
156 | rsm.setIndex(initialIndex);
157 |
158 | if (!filteredList.isEmpty()) {
159 | rsm.setFirst(filteredList.get(0).getId());
160 | rsm.setLast(filteredList.get(filteredList.size() - 1).getId());
161 | }
162 |
163 | return filteredList;
164 | }
165 |
166 | }
167 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/handler/nearby/NearbyQueryHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.handler.nearby;
17 |
18 | import java.net.MalformedURLException;
19 | import java.util.ArrayList;
20 | import java.util.List;
21 | import java.util.Properties;
22 |
23 | import org.apache.solr.client.solrj.SolrQuery;
24 | import org.apache.solr.client.solrj.SolrQuery.ORDER;
25 | import org.apache.solr.client.solrj.SolrServer;
26 | import org.apache.solr.client.solrj.SolrServerException;
27 | import org.apache.solr.client.solrj.response.QueryResponse;
28 | import org.apache.solr.common.SolrDocument;
29 | import org.apache.solr.common.SolrDocumentList;
30 | import org.dom4j.Attribute;
31 | import org.dom4j.Element;
32 | import org.xmpp.packet.IQ;
33 |
34 | import com.buddycloud.channeldirectory.commons.solr.SolrServerFactory;
35 | import com.buddycloud.channeldirectory.search.handler.common.ChannelQueryHandler;
36 | import com.buddycloud.channeldirectory.search.handler.response.ChannelData;
37 | import com.buddycloud.channeldirectory.search.handler.response.Geolocation;
38 | import com.buddycloud.channeldirectory.search.rsm.RSM;
39 | import com.buddycloud.channeldirectory.search.rsm.RSMUtils;
40 | import com.buddycloud.channeldirectory.search.rsm.SolrRSMUtils;
41 | import com.buddycloud.channeldirectory.search.utils.XMPPUtils;
42 |
43 | /**
44 | * Handles queries for nearby content.
45 | * A query should contain user's lat/lon pair, so
46 | * this handle can return channels close to user location.
47 | * Returns the closest channels (in ascending distance order)
48 | * in a 1000km radius.
49 | */
50 | public class NearbyQueryHandler extends ChannelQueryHandler {
51 |
52 | private static final String RADIUS_IN_KM = "1000";
53 |
54 | public NearbyQueryHandler(Properties properties) {
55 | super("http://buddycloud.com/channel_directory/nearby_query", properties);
56 | }
57 |
58 | @Override
59 | public IQ handle(IQ iq) {
60 |
61 | Element queryElement = iq.getElement().element("query");
62 | Element pointElement = queryElement.element("point");
63 |
64 | if (pointElement == null) {
65 | return XMPPUtils.error(iq, "Query does not contain point element.",
66 | getLogger());
67 | }
68 |
69 | Attribute latAtt = pointElement.attribute("lat");
70 | if (latAtt == null) {
71 | return XMPPUtils.error(iq,
72 | "Location point does not contain point latitude element.",
73 | getLogger());
74 | }
75 |
76 | Attribute lngAtt = pointElement.attribute("lon");
77 | if (lngAtt == null) {
78 | return XMPPUtils.error(iq,
79 | "Location point does not contain point longitude element.",
80 | getLogger());
81 | }
82 |
83 | double lat = Double.valueOf(latAtt.getValue());
84 | double lng = Double.valueOf(lngAtt.getValue());
85 |
86 | RSM rsm = RSMUtils.parseRSM(queryElement);
87 | List nearbyObjects;
88 |
89 | try {
90 | nearbyObjects = findNearbyObjects(lat, lng, rsm);
91 | } catch (Exception e) {
92 | return XMPPUtils.error(iq, "Search could not be performed, service is unavailable.",
93 | getLogger());
94 | }
95 |
96 | return createIQResponse(iq, nearbyObjects, rsm);
97 | }
98 |
99 | private List findNearbyObjects(double lat, double lng, RSM rsm) throws MalformedURLException, SolrServerException {
100 | SolrServer solrServer = new SolrServerFactory().createChannelCore(getProperties());
101 | SolrQuery solrQuery = new SolrQuery("*:*");
102 | solrQuery.set("fq", "{!geofilt}");
103 | solrQuery.set("sfield", "geoloc");
104 | solrQuery.set("pt", lat + "," + lng);
105 | solrQuery.set("d", RADIUS_IN_KM);
106 |
107 | solrQuery.addSortField("geodist()", ORDER.asc);
108 |
109 | SolrRSMUtils.preprocess(solrQuery, rsm);
110 | QueryResponse queryResponse = solrServer.query(solrQuery);
111 | SolrRSMUtils.postprocess(queryResponse, rsm);
112 |
113 | return convertResponse(queryResponse);
114 | }
115 |
116 | private static List convertResponse(QueryResponse queryResponse) {
117 | List channels = new ArrayList();
118 | SolrDocumentList results = queryResponse.getResults();
119 |
120 | for (SolrDocument solrDocument : results) {
121 | channels.add(convertDocument(solrDocument));
122 | }
123 |
124 | return channels;
125 | }
126 |
127 | private static ChannelData convertDocument(SolrDocument solrDocument) {
128 | ChannelData channelData = new ChannelData();
129 | String latLonStr = (String) solrDocument.getFieldValue("geoloc");
130 | if (latLonStr != null) {
131 | String[] latLonSplit = latLonStr.split(",");
132 | channelData.setGeolocation(new Geolocation(
133 | Double.parseDouble(latLonSplit[0]),
134 | Double.parseDouble(latLonSplit[1])));
135 | }
136 |
137 | channelData.setId((String) solrDocument.getFieldValue("jid"));
138 | channelData.setTitle((String) solrDocument.getFieldValue("title"));
139 | return channelData;
140 | }
141 |
142 | }
143 |
--------------------------------------------------------------------------------
/src/test/java/com/buddycloud/channeldirectory/rsm/RSMTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.rsm;
17 |
18 | import java.util.LinkedList;
19 | import java.util.List;
20 |
21 | import org.junit.Assert;
22 | import org.junit.Test;
23 |
24 | import com.buddycloud.channeldirectory.search.handler.response.ChannelData;
25 | import com.buddycloud.channeldirectory.search.rsm.RSM;
26 | import com.buddycloud.channeldirectory.search.rsm.RSMUtils;
27 |
28 | public class RSMTest {
29 |
30 | private static final int TEST_DATA_SIZE = 20;
31 |
32 | @Test
33 | public void testNoRSMInfo() {
34 | RSM rsm = new RSM();
35 | List response = RSMUtils.filterRSMResponse(
36 | createTestData(), rsm);
37 |
38 | Assert.assertEquals(TEST_DATA_SIZE, response.size());
39 | Assert.assertEquals(0, rsm.getIndex().intValue());
40 | Assert.assertEquals(TEST_DATA_SIZE, rsm.getCount().intValue());
41 | Assert.assertEquals("jid0", rsm.getFirst());
42 | Assert.assertEquals("jid19", rsm.getLast());
43 | }
44 |
45 | @Test
46 | public void testLimitToResultSet() {
47 | RSM rsm = new RSM();
48 | rsm.setMax(10);
49 | List response = RSMUtils.filterRSMResponse(
50 | createTestData(), rsm);
51 |
52 | Assert.assertEquals(10, response.size());
53 | Assert.assertEquals(0, rsm.getIndex().intValue());
54 | Assert.assertEquals(TEST_DATA_SIZE, rsm.getCount().intValue());
55 | Assert.assertEquals("jid0", rsm.getFirst());
56 | Assert.assertEquals("jid9", rsm.getLast());
57 | }
58 |
59 | @Test
60 | public void testPaging() {
61 | RSM rsm = new RSM();
62 | rsm.setMax(10);
63 | rsm.setAfter("jid9");
64 | List response = RSMUtils.filterRSMResponse(
65 | createTestData(), rsm);
66 |
67 | Assert.assertEquals(10, response.size());
68 | Assert.assertEquals(10, rsm.getIndex().intValue());
69 | Assert.assertEquals(TEST_DATA_SIZE, rsm.getCount().intValue());
70 | Assert.assertEquals("jid10", rsm.getFirst());
71 | Assert.assertEquals("jid19", rsm.getLast());
72 | }
73 |
74 | @Test
75 | public void testBlankPage() {
76 | RSM rsm = new RSM();
77 | rsm.setMax(10);
78 | rsm.setAfter("jid19");
79 | List response = RSMUtils.filterRSMResponse(
80 | createTestData(), rsm);
81 |
82 | Assert.assertEquals(0, response.size());
83 | Assert.assertEquals(TEST_DATA_SIZE, rsm.getCount().intValue());
84 | Assert.assertNull(rsm.getFirst());
85 | Assert.assertNull(rsm.getLast());
86 | }
87 |
88 | @Test
89 | public void testPagingBackwards() {
90 | RSM rsm = new RSM();
91 | rsm.setMax(10);
92 | rsm.setBefore("jid15");
93 | List response = RSMUtils.filterRSMResponse(
94 | createTestData(), rsm);
95 |
96 | Assert.assertEquals(10, response.size());
97 | Assert.assertEquals(5, rsm.getIndex().intValue());
98 | Assert.assertEquals(TEST_DATA_SIZE, rsm.getCount().intValue());
99 | Assert.assertEquals("jid5", rsm.getFirst());
100 | Assert.assertEquals("jid14", rsm.getLast());
101 | }
102 |
103 | @Test(expected=IllegalArgumentException.class)
104 | public void testPageNotFound() {
105 | RSM rsm = new RSM();
106 | rsm.setMax(10);
107 | rsm.setAfter("jid20");
108 | RSMUtils.filterRSMResponse(createTestData(), rsm);
109 | }
110 |
111 | @Test
112 | public void testLastPage() {
113 | RSM rsm = new RSM();
114 | rsm.setMax(10);
115 | rsm.setBefore("");
116 | List response = RSMUtils.filterRSMResponse(
117 | createTestData(), rsm);
118 |
119 | Assert.assertEquals(10, response.size());
120 | Assert.assertEquals(10, rsm.getIndex().intValue());
121 | Assert.assertEquals(TEST_DATA_SIZE, rsm.getCount().intValue());
122 | Assert.assertEquals("jid10", rsm.getFirst());
123 | Assert.assertEquals("jid19", rsm.getLast());
124 | }
125 |
126 | @Test
127 | public void testPageOutOfOrder() {
128 | RSM rsm = new RSM();
129 | rsm.setMax(10);
130 | rsm.setIndex(5);
131 | List response = RSMUtils.filterRSMResponse(
132 | createTestData(), rsm);
133 |
134 | Assert.assertEquals(10, response.size());
135 | Assert.assertEquals(5, rsm.getIndex().intValue());
136 | Assert.assertEquals(TEST_DATA_SIZE, rsm.getCount().intValue());
137 | Assert.assertEquals("jid5", rsm.getFirst());
138 | Assert.assertEquals("jid14", rsm.getLast());
139 | }
140 |
141 | @Test
142 | public void testGettingItemCount() {
143 | RSM rsm = new RSM();
144 | rsm.setMax(0);
145 | List response = RSMUtils.filterRSMResponse(
146 | createTestData(), rsm);
147 |
148 | Assert.assertEquals(0, response.size());
149 | Assert.assertEquals(TEST_DATA_SIZE, rsm.getCount().intValue());
150 | Assert.assertEquals(null, rsm.getFirst());
151 | Assert.assertEquals(null, rsm.getLast());
152 | }
153 |
154 | private static List createTestData() {
155 | List objects = new LinkedList();
156 | for (int i = 0; i < TEST_DATA_SIZE; i++) {
157 | ChannelData object = new ChannelData();
158 | object.setId("jid" + i);
159 | objects.add(object);
160 | }
161 |
162 | return objects;
163 | }
164 |
165 | }
166 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/handler/content/ContentQueryHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.handler.content;
17 |
18 | import java.net.MalformedURLException;
19 | import java.util.ArrayList;
20 | import java.util.Date;
21 | import java.util.List;
22 | import java.util.Properties;
23 |
24 | import org.apache.solr.client.solrj.SolrQuery;
25 | import org.apache.solr.client.solrj.SolrQuery.ORDER;
26 | import org.apache.solr.client.solrj.SolrServer;
27 | import org.apache.solr.client.solrj.SolrServerException;
28 | import org.apache.solr.client.solrj.response.QueryResponse;
29 | import org.apache.solr.common.SolrDocument;
30 | import org.apache.solr.common.SolrDocumentList;
31 | import org.dom4j.Element;
32 | import org.xmpp.packet.IQ;
33 |
34 | import com.buddycloud.channeldirectory.commons.solr.SolrServerFactory;
35 | import com.buddycloud.channeldirectory.search.handler.common.PostQueryHandler;
36 | import com.buddycloud.channeldirectory.search.handler.response.Geolocation;
37 | import com.buddycloud.channeldirectory.search.handler.response.PostData;
38 | import com.buddycloud.channeldirectory.search.rsm.RSM;
39 | import com.buddycloud.channeldirectory.search.rsm.RSMUtils;
40 | import com.buddycloud.channeldirectory.search.rsm.SolrRSMUtils;
41 | import com.buddycloud.channeldirectory.search.utils.XMPPUtils;
42 |
43 | /**
44 | * Handles queries for content posts.
45 | * A query should contain a content query string, so
46 | * this handle can return channel posts related to this search.
47 | *
48 | */
49 | public class ContentQueryHandler extends PostQueryHandler {
50 |
51 | public ContentQueryHandler(Properties properties) {
52 | super("http://buddycloud.com/channel_directory/content_query", properties);
53 | }
54 |
55 | @Override
56 | public IQ handle(IQ iq) {
57 |
58 | Element queryElement = iq.getElement().element("query");
59 | Element searchElement = queryElement.element("search");
60 |
61 | if (searchElement == null) {
62 | return XMPPUtils.error(iq, "Query does not contain search element.",
63 | getLogger());
64 | }
65 |
66 | String search = searchElement.getText();
67 |
68 | if (search == null || search.isEmpty()) {
69 | return XMPPUtils.error(iq, "Search content cannot be empty.",
70 | getLogger());
71 | }
72 |
73 | RSM rsm = RSMUtils.parseRSM(queryElement);
74 | List relatedPosts;
75 |
76 | try {
77 | relatedPosts = findObjectsByContent(search, rsm);
78 | } catch (Exception e) {
79 | return XMPPUtils.error(iq, "Search could not be performed, service is unavailable.",
80 | e, getLogger());
81 | }
82 |
83 | return createIQResponse(iq, relatedPosts, rsm);
84 | }
85 |
86 | private List findObjectsByContent(String search, RSM rsm)
87 | throws MalformedURLException, SolrServerException {
88 | SolrServer solrServer = new SolrServerFactory().createPostCore(
89 | getProperties());
90 | SolrQuery solrQuery = new SolrQuery(search);
91 | solrQuery.setSortField("updated", ORDER.desc);
92 |
93 | SolrRSMUtils.preprocess(solrQuery, rsm);
94 | QueryResponse queryResponse = solrServer.query(solrQuery);
95 | SolrRSMUtils.postprocess(queryResponse, rsm);
96 |
97 | return convertResponse(queryResponse);
98 | }
99 |
100 | private static List convertResponse(QueryResponse queryResponse) {
101 | List channels = new ArrayList();
102 | SolrDocumentList results = queryResponse.getResults();
103 |
104 | for (SolrDocument solrDocument : results) {
105 | channels.add(convertDocument(solrDocument));
106 | }
107 |
108 | return channels;
109 | }
110 |
111 | private static PostData convertDocument(SolrDocument solrDocument) {
112 | PostData postData = new PostData();
113 |
114 | String latLonStr = (String) solrDocument.getFieldValue("geoloc");
115 | String locStr = (String) solrDocument.getFieldValue("geoloc_text");
116 |
117 | if (latLonStr != null || locStr != null) {
118 | Geolocation geoLocation = new Geolocation();
119 | geoLocation.setText(locStr);
120 |
121 | if (latLonStr != null) {
122 | String[] latLonSplit = latLonStr.split(",");
123 | geoLocation.setLat(Double.parseDouble(latLonSplit[0]));
124 | geoLocation.setLng(Double.parseDouble(latLonSplit[1]));
125 | }
126 |
127 | postData.setGeolocation(geoLocation);
128 | }
129 |
130 | postData.setId((String) solrDocument.getFieldValue("id"));
131 | postData.setAuthor((String) solrDocument.getFieldValue("author"));
132 | postData.setContent((String) solrDocument.getFieldValue("content"));
133 | postData.setServerId((String) solrDocument.getFieldValue("server_id"));
134 | postData.setParentSimpleId((String) solrDocument.getFieldValue("parent_simpleid"));
135 | postData.setParentFullId((String) solrDocument.getFieldValue("parent_fullid"));
136 | postData.setInReplyTo((String) solrDocument.getFieldValue("inreplyto"));
137 | postData.setUpdated((Date) solrDocument.getFieldValue("updated"));
138 | postData.setPublished((Date) solrDocument.getFieldValue("published"));
139 |
140 | return postData;
141 | }
142 |
143 | }
144 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/ChannelDirectoryComponent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search;
17 |
18 | import java.beans.PropertyVetoException;
19 | import java.util.ArrayList;
20 | import java.util.HashMap;
21 | import java.util.Map;
22 | import java.util.Properties;
23 |
24 | import org.apache.log4j.Logger;
25 | import org.dom4j.Element;
26 | import org.dom4j.Namespace;
27 | import org.xmpp.component.AbstractComponent;
28 | import org.xmpp.packet.IQ;
29 | import org.xmpp.packet.Packet;
30 |
31 | import com.buddycloud.channeldirectory.commons.db.ChannelDirectoryDataSource;
32 | import com.buddycloud.channeldirectory.search.handler.QueryHandler;
33 | import com.buddycloud.channeldirectory.search.handler.active.MostActiveQueryHandler;
34 | import com.buddycloud.channeldirectory.search.handler.common.mahout.ChannelRecommender;
35 | import com.buddycloud.channeldirectory.search.handler.content.ContentQueryHandler;
36 | import com.buddycloud.channeldirectory.search.handler.metadata.MetadataQueryHandler;
37 | import com.buddycloud.channeldirectory.search.handler.nearby.NearbyQueryHandler;
38 | import com.buddycloud.channeldirectory.search.handler.recommendation.RecommendationQueryHandler;
39 | import com.buddycloud.channeldirectory.search.handler.similarity.SimilarityQueryHandler;
40 | import com.buddycloud.channeldirectory.search.rsm.RSM;
41 | import com.buddycloud.channeldirectory.search.utils.XMPPUtils;
42 |
43 | /**
44 | * Channel Directory XMPP Component
45 | * Follows the XEP-0114 (http://xmpp.org/extensions/xep-0114.html)
46 | *
47 | */
48 | public class ChannelDirectoryComponent extends AbstractComponent {
49 |
50 | private static final String DESCRIPTION = "A pub sub search engine, " +
51 | "metadata crawler and recommendation service";
52 | private static final String NAME = "Channel Directory";
53 | private static final Logger LOGGER = Logger.getLogger(ChannelDirectoryComponent.class);
54 |
55 | private final Map queryHandlers = new HashMap();
56 | private final Properties properties;
57 |
58 | public ChannelDirectoryComponent(Properties properties) {
59 | this.properties = properties;
60 | }
61 |
62 | @Override
63 | public String getDescription() {
64 | return DESCRIPTION;
65 | }
66 |
67 | @Override
68 | public String getName() {
69 | return NAME;
70 | }
71 |
72 | @Override
73 | public void postComponentStart() {
74 | createHandlers();
75 | }
76 |
77 | /* (non-Javadoc)
78 | * @see org.xmpp.component.AbstractComponent#send(org.xmpp.packet.Packet)
79 | */
80 | @Override
81 | protected void send(Packet arg0) {
82 | LOGGER.debug("S: " + arg0.toXML());
83 | super.send(arg0);
84 | }
85 |
86 | @Override
87 | protected IQ handleIQGet(IQ iq) throws Exception {
88 |
89 | LOGGER.debug("R: " + iq.toXML());
90 |
91 | Element queryElement = iq.getElement().element("query");
92 | if (queryElement == null) {
93 | return XMPPUtils.error(iq, "IQ does not contain query element.",
94 | LOGGER);
95 | }
96 |
97 | Namespace namespace = queryElement.getNamespace();
98 |
99 | QueryHandler queryHandler = queryHandlers.get(namespace.getURI());
100 | if (queryHandler == null) {
101 | return XMPPUtils.error(iq, "QueryHandler not found for namespace: " + namespace,
102 | LOGGER);
103 | }
104 |
105 | return queryHandler.handle(iq);
106 | }
107 |
108 | @Override
109 | protected String[] discoInfoFeatureNamespaces() {
110 | ArrayList namespaces = new ArrayList(queryHandlers.keySet());
111 | namespaces.add(RSM.NAMESPACE);
112 | return (namespaces.toArray(new String[]{}));
113 | }
114 |
115 | @Override
116 | protected String discoInfoIdentityCategory() {
117 | return ("Search");
118 | }
119 |
120 | @Override
121 | protected String discoInfoIdentityCategoryType() {
122 | return ("Directory");
123 | }
124 |
125 | private void createHandlers() {
126 |
127 | ChannelDirectoryDataSource dataSource = null;
128 | try {
129 | dataSource = new ChannelDirectoryDataSource(properties);
130 | } catch (PropertyVetoException e) {
131 | throw new RuntimeException("Could not start data source", e);
132 | }
133 |
134 | addHandler(new NearbyQueryHandler(properties));
135 | addHandler(new MetadataQueryHandler(properties));
136 | addHandler(new ContentQueryHandler(properties));
137 | addHandler(new MostActiveQueryHandler(properties, dataSource));
138 |
139 | try {
140 | ChannelRecommender recommender = createRecommender(properties);
141 | addHandler(new RecommendationQueryHandler(properties, recommender));
142 | addHandler(new SimilarityQueryHandler(properties, recommender));
143 | } catch (Exception e) {
144 | LOGGER.warn("Could not create mahout-related handlers.", e);
145 | }
146 | }
147 |
148 | private ChannelRecommender createRecommender(Properties properties) {
149 | try {
150 | return new ChannelRecommender(properties);
151 | } catch (Exception e) {
152 | throw new RuntimeException(e);
153 | }
154 | }
155 |
156 | private void addHandler(QueryHandler queryHandler) {
157 | queryHandlers.put(queryHandler.getNamespace(), queryHandler);
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/handler/common/mahout/PostgreSQLRecommenderDataModel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.handler.common.mahout;
17 |
18 | import java.sql.Connection;
19 | import java.sql.PreparedStatement;
20 | import java.sql.ResultSet;
21 | import java.sql.SQLException;
22 | import java.util.LinkedList;
23 | import java.util.Properties;
24 | import java.util.concurrent.Executors;
25 | import java.util.concurrent.ScheduledExecutorService;
26 | import java.util.concurrent.TimeUnit;
27 |
28 | import org.apache.log4j.Logger;
29 | import org.apache.mahout.cf.taste.common.Refreshable;
30 | import org.apache.mahout.cf.taste.common.TasteException;
31 | import org.apache.mahout.cf.taste.impl.model.jdbc.PostgreSQLBooleanPrefJDBCDataModel;
32 | import org.apache.mahout.cf.taste.impl.model.jdbc.ReloadFromJDBCDataModel;
33 | import org.apache.mahout.cf.taste.model.DataModel;
34 |
35 | import com.buddycloud.channeldirectory.commons.db.ChannelDirectoryDataSource;
36 | import com.buddycloud.channeldirectory.search.handler.response.ChannelData;
37 |
38 | /**
39 | * Reads taste data from a PostgreSQL database and stores
40 | * it in memory. Whenever the database is updated, the data model
41 | * reloads the updated data.
42 | *
43 | */
44 | public class PostgreSQLRecommenderDataModel implements ChannelRecommenderDataModel {
45 |
46 | private static Logger LOGGER = Logger.getLogger(PostgreSQLRecommenderDataModel.class);
47 |
48 | private static final int REFRESH_DELAY = 30; // Minutes
49 |
50 | private ChannelDirectoryDataSource dataSource;
51 | private DataModel dataModel;
52 |
53 | public PostgreSQLRecommenderDataModel(Properties properties) {
54 | try {
55 | dataSource = new ChannelDirectoryDataSource(properties);
56 | createDataModel();
57 | scheduleRefreshAction();
58 | } catch (Exception e) {
59 | throw new RuntimeException(e);
60 | }
61 | }
62 |
63 | private void createDataModel() throws TasteException {
64 | this.dataModel = new ReloadFromJDBCDataModel(
65 | new PostgreSQLBooleanPrefJDBCDataModel(
66 | dataSource.getDataSource()));
67 | }
68 |
69 | private void scheduleRefreshAction() {
70 | ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1);
71 | scheduledThreadPool.scheduleWithFixedDelay(new Runnable() {
72 | @Override
73 | public void run() {
74 | try {
75 | dataModel.refresh(new LinkedList());
76 | } catch (Throwable t) {
77 | LOGGER.warn("Could not reload mahout JDBC model.", t);
78 | }
79 | }
80 | }, REFRESH_DELAY, REFRESH_DELAY, TimeUnit.MINUTES);
81 | }
82 |
83 | @Override
84 | public DataModel getDataModel() {
85 | return dataModel;
86 | }
87 |
88 | @Override
89 | public Long toUserId(String userJid) {
90 |
91 | PreparedStatement statement = null;
92 |
93 | try {
94 | Connection connection = dataSource.getConnection();
95 | statement = connection
96 | .prepareStatement("SELECT id FROM t_user WHERE jid = ?");
97 | statement.setString(1, userJid);
98 |
99 | ResultSet resultSet = statement.executeQuery();
100 | if (resultSet.next()) {
101 | return resultSet.getLong("id");
102 | }
103 | return null;
104 | } catch (SQLException e) {
105 | throw new RuntimeException(e);
106 | } finally {
107 | close(statement);
108 | }
109 | }
110 |
111 | /**
112 | * @param statement
113 | */
114 | private void close(PreparedStatement statement) {
115 | if (statement == null) {
116 | return;
117 | }
118 |
119 | try {
120 | Connection connection = statement.getConnection();
121 | statement.close();
122 | if (connection != null) {
123 | connection.close();
124 | }
125 |
126 | } catch (SQLException e) {
127 | throw new RuntimeException(e);
128 | }
129 | }
130 |
131 | @Override
132 | public ChannelData toChannelData(long itemID) {
133 |
134 | PreparedStatement statement = null;
135 |
136 | try {
137 | Connection connection = dataSource.getConnection();
138 |
139 | statement = connection
140 | .prepareStatement("SELECT jid, title, description FROM item WHERE id = ?");
141 |
142 | statement.setLong(1, itemID);
143 |
144 | ResultSet resultSet = statement.executeQuery();
145 | resultSet.next();
146 |
147 | String jid = resultSet.getString("jid");
148 | String title = resultSet.getString("title");
149 | String desc = resultSet.getString("description");
150 |
151 | ChannelData channelData = new ChannelData();
152 | channelData.setId(jid);
153 | channelData.setTitle(title);
154 | channelData.setDescription(desc);
155 |
156 | return channelData;
157 | } catch (SQLException e) {
158 | throw new RuntimeException(e);
159 | } finally {
160 | close(statement);
161 | }
162 | }
163 |
164 | @Override
165 | public Long toChannelId(String channelJid) {
166 |
167 | PreparedStatement statement = null;
168 |
169 | try {
170 | Connection connection = dataSource.getConnection();
171 |
172 | statement = connection
173 | .prepareStatement("SELECT id FROM item WHERE jid = ?");
174 | statement.setString(1, channelJid);
175 |
176 | ResultSet resultSet = statement.executeQuery();
177 | if (resultSet.next()) {
178 | return resultSet.getLong("id");
179 | }
180 |
181 | return null;
182 | } catch (SQLException e) {
183 | throw new RuntimeException(e);
184 | } finally {
185 | close(statement);
186 | }
187 | }
188 |
189 | }
190 |
--------------------------------------------------------------------------------
/resources/solr/multicore/channels/conf/schema.xml:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
36 |
37 |
38 |
39 |
42 |
46 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 | jid
95 |
96 |
97 | text
98 |
99 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/src/main/java/com/buddycloud/channeldirectory/search/handler/common/mahout/ChannelRecommender.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 buddycloud
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.buddycloud.channeldirectory.search.handler.common.mahout;
17 |
18 | import java.sql.SQLException;
19 | import java.util.LinkedList;
20 | import java.util.List;
21 | import java.util.Properties;
22 |
23 | import org.apache.mahout.cf.taste.common.TasteException;
24 | import org.apache.mahout.cf.taste.impl.common.FastIDSet;
25 | import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
26 | import org.apache.mahout.cf.taste.impl.recommender.GenericBooleanPrefUserBasedRecommender;
27 | import org.apache.mahout.cf.taste.impl.recommender.GenericItemBasedRecommender.MostSimilarEstimator;
28 | import org.apache.mahout.cf.taste.impl.recommender.PreferredItemsNeighborhoodCandidateItemsStrategy;
29 | import org.apache.mahout.cf.taste.impl.recommender.TopItems;
30 | import org.apache.mahout.cf.taste.impl.similarity.CachingUserSimilarity;
31 | import org.apache.mahout.cf.taste.impl.similarity.LogLikelihoodSimilarity;
32 | import org.apache.mahout.cf.taste.model.DataModel;
33 | import org.apache.mahout.cf.taste.recommender.MostSimilarItemsCandidateItemsStrategy;
34 | import org.apache.mahout.cf.taste.recommender.RecommendedItem;
35 | import org.apache.mahout.cf.taste.recommender.Recommender;
36 | import org.apache.mahout.cf.taste.similarity.UserSimilarity;
37 |
38 | import com.buddycloud.channeldirectory.search.handler.response.ChannelData;
39 |
40 | /**
41 | * Mahout based user-recommender for channels.
42 | * Uses the {@link GenericBooleanPrefUserBasedRecommender} with
43 | * a {@link LogLikelihoodSimilarity} for the user similarity.
44 | *
45 | */
46 | public class ChannelRecommender {
47 |
48 | /**
49 | *
50 | */
51 | private static final int MAX_CACHE_SIZE = 100000;
52 | private static final String POSTGRESQL_MODEL = "postgresql";
53 | private static final String INMEMORY_MODEL = "memory";
54 |
55 | private Recommender userRecommender;
56 | private ChannelRecommenderDataModel recommenderDataModel;
57 |
58 | private NearestNUserNeighborhood userNeighborhood;
59 | private LogLikelihoodSimilarity itemSimilarity;
60 |
61 | public ChannelRecommender(Properties properties) throws TasteException {
62 |
63 | this.recommenderDataModel = createDataModel(properties);
64 | DataModel dataModel = recommenderDataModel.getDataModel();
65 |
66 | UserSimilarity userSimilarity = new CachingUserSimilarity(
67 | new LogLikelihoodSimilarity(dataModel), MAX_CACHE_SIZE);
68 | this.userNeighborhood = new NearestNUserNeighborhood(10,
69 | Double.NEGATIVE_INFINITY, userSimilarity, dataModel, 1.0);
70 | this.userRecommender = new GenericBooleanPrefUserBasedRecommender(dataModel,
71 | userNeighborhood, userSimilarity);
72 |
73 | this.itemSimilarity = new LogLikelihoodSimilarity(dataModel);
74 | }
75 |
76 | private ChannelRecommenderDataModel createDataModel(Properties properties) {
77 | String recommenderModel = properties.getProperty("mahout.recommender");
78 | if (recommenderModel.equals(INMEMORY_MODEL)) {
79 | return new MemoryRecommenderDataModel(properties);
80 | }
81 |
82 | if (recommenderModel.equals(POSTGRESQL_MODEL)) {
83 | return new PostgreSQLRecommenderDataModel(properties);
84 | }
85 |
86 | return null;
87 | }
88 |
89 | /**
90 | * Recommends a list of jids of channels that are
91 | * related to the user taste.
92 | *
93 | * @param userJid The user jid
94 | * @param howMany The number of recommendations
95 | * @return A list of recommended channels' jids
96 | * @throws TasteException
97 | * @throws SQLException
98 | */
99 | public RecommendationResponse recommend(String userJid, int howMany)
100 | throws TasteException, SQLException {
101 | Long userId = recommenderDataModel.toUserId(userJid);
102 |
103 | if (userId == null) {
104 | return new RecommendationResponse(new LinkedList(), 0);
105 | }
106 |
107 | List recommended = userRecommender.recommend(
108 | userId, howMany);
109 |
110 | List recommendedChannels = new LinkedList();
111 |
112 | for (RecommendedItem recommendedItem : recommended) {
113 | recommendedChannels.add(recommenderDataModel.toChannelData(
114 | recommendedItem.getItemID()));
115 | }
116 |
117 | return new RecommendationResponse(recommendedChannels,
118 | getPreferenceCount(userId));
119 | }
120 |
121 | /**
122 | * Recommends a list of jids of channels that are
123 | * similar to a given channel.
124 | *
125 | * @param channelJid The channel jid
126 | * @param howMany The number of recommendations
127 | * @return A list of similar channels' jids
128 | * @throws TasteException
129 | * @throws SQLException
130 | */
131 | public RecommendationResponse getSimilarChannels(String channelJid, int howMany)
132 | throws TasteException, SQLException {
133 |
134 | Long itemId = recommenderDataModel.toChannelId(channelJid);
135 |
136 | if (itemId == null) {
137 | return new RecommendationResponse(new LinkedList(), 0);
138 | }
139 |
140 | TopItems.Estimator estimator = new MostSimilarEstimator(
141 | itemId, itemSimilarity, null);
142 | MostSimilarItemsCandidateItemsStrategy candidateStrategy = new PreferredItemsNeighborhoodCandidateItemsStrategy();
143 |
144 | FastIDSet possibleItemIDs = candidateStrategy.getCandidateItems(
145 | new long[] {itemId}, recommenderDataModel.getDataModel());
146 | List recommended = TopItems.getTopItems(
147 | howMany, possibleItemIDs.iterator(), null, estimator);
148 |
149 | List recommendedChannels = new LinkedList();
150 |
151 | for (RecommendedItem recommendedItem : recommended) {
152 | recommendedChannels.add(recommenderDataModel.toChannelData(
153 | recommendedItem.getItemID()));
154 | }
155 |
156 | return new RecommendationResponse(recommendedChannels,
157 | possibleItemIDs.size());
158 | }
159 |
160 | private int getPreferenceCount(long theUserId) throws TasteException {
161 | FastIDSet possibleItemIDs = new FastIDSet();
162 | long[] theNeighborhood = userNeighborhood.getUserNeighborhood(theUserId);
163 | DataModel dataModel = recommenderDataModel.getDataModel();
164 |
165 | for (long userID : theNeighborhood) {
166 | possibleItemIDs.addAll(dataModel.getItemIDsFromUser(userID));
167 | }
168 | possibleItemIDs.removeAll(dataModel.getItemIDsFromUser(theUserId));
169 |
170 | return possibleItemIDs.size();
171 | }
172 | }
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | buddycloud-channel-directory
5 | buddycloud-channel-directory
6 | jar
7 | 0.0.1-SNAPSHOT
8 |
9 |
10 | org.apache.solr
11 | solr-solrj
12 | 3.1.0
13 |
14 |
15 |
16 | c3p0
17 | c3p0
18 | 0.9.1.2
19 |
20 |
21 | commons-cli
22 | commons-cli
23 | 1.2
24 |
25 |
26 | commons-codec
27 | commons-codec
28 | 1.4
29 |
30 |
31 | commons-httpclient
32 | commons-httpclient
33 | 3.1
34 |
35 |
36 | commons-io
37 | commons-io
38 | 1.4
39 |
40 |
41 | com.googlecode.concurrentlinkedhashmap
42 | concurrentlinkedhashmap-lru
43 | 1.1
44 |
45 |
46 | dnsjava
47 | dnsjava
48 | 2.1.6
49 |
50 |
51 | dom4j
52 | dom4j
53 | 1.6.1
54 |
55 |
56 | com.google.collections
57 | google-collections
58 | 1.0-rc2
59 |
60 |
61 | junit
62 | junit
63 | 4.8.1
64 | test
65 |
66 |
67 | com.google.code.gson
68 | gson
69 | 2.2.1
70 |
71 |
72 | com.google.guava
73 | guava
74 | r03
75 |
76 |
77 | org.hsqldb
78 | hsqldb
79 | 2.3.2
80 | test
81 |
82 |
83 | org.slf4j
84 | jcl-over-slf4j
85 | 1.5.5
86 |
87 |
88 | org.gnu.inet
89 | libidn
90 | 1.15
91 |
92 |
93 | log4j
94 | log4j
95 | 1.2.15
96 |
97 |
98 | com.sun.jmx
99 | jmxri
100 |
101 |
102 | com.sun.jdmk
103 | jmxtools
104 |
105 |
106 | javax.jms
107 | jms
108 |
109 |
110 |
111 |
112 | org.apache.mahout
113 | mahout-core
114 | 0.5
115 |
116 |
117 | org.apache.mahout
118 | mahout-math
119 | 0.5
120 |
121 |
122 | org.mockito
123 | mockito-all
124 | 1.9.5
125 | test
126 |
127 |
128 | net.sf.opencsv
129 | opencsv
130 | 2.3
131 |
132 |
133 | postgresql
134 | postgresql
135 | 9.0-801.jdbc4
136 |
137 |
138 | org.slf4j
139 | slf4j-api
140 | 1.5.8
141 |
142 |
143 | org.slf4j
144 | slf4j-log4j12
145 | 1.5.8
146 |
147 |
148 |
149 | org.igniterealtime.smack
150 | smack-java7
151 | 4.1.0-alpha2
152 |
153 |
154 | org.igniterealtime.smack
155 | smack-extensions
156 | 4.1.0-alpha2
157 |
158 |
159 | org.igniterealtime.smack
160 | smack-tcp
161 | 4.1.0-alpha2
162 |
163 |
164 |
165 | org.igniterealtime
166 | tinder
167 | 1.2.2
168 |
169 |
170 | org.uncommons.maths
171 | uncommons-maths
172 | 1.2
173 |
174 |
175 |
176 | org.igniterealtime
177 | whack
178 | 1.0.0
179 |
180 |
181 | xpp3
182 | xpp3
183 | 1.1.4c
184 |
185 |
186 |
187 |
188 |
189 | maven-compiler-plugin
190 | 3.0
191 |
192 |
193 |
194 |
195 |
196 |
197 | org.apache.maven.plugins
198 | maven-compiler-plugin
199 | 2.5.1
200 |
201 | 1.7
202 | 1.7
203 |
204 |
205 |
206 | maven-assembly-plugin
207 |
208 |
209 | jar-with-dependencies
210 |
211 |
212 |
213 |
214 | make-assembly
215 | package
216 |
217 | single
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 | local
227 | file://${basedir}/.m2
228 |
229 |
230 |
231 |
--------------------------------------------------------------------------------