Skip to content

Commit 04f5219

Browse files
committed
multitenancy (#195)
1 parent a460072 commit 04f5219

19 files changed

+1099
-0
lines changed

appengine/multitenancy/README.md

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Multitenancy Java sample
2+
3+
Shows the usage of the Namespaces API.
4+
5+
An App Engine guestbook using Java, Maven, and Objectify.
6+
7+
Data access using [Objectify](https://github.com/objectify/objectify)
8+
9+
Please ask questions on [Stackoverflow](http://stackoverflow.com/questions/tagged/google-app-engine)
10+
11+
## Running Locally
12+
13+
How do I, as a developer, start working on the project?
14+
15+
1. `mvn clean appengine:devserver`
16+
17+
## Deploying
18+
19+
1. `mvn clean appengine:update -Dappengine.appId=PROJECT -Dappengine.version=VERSION`

appengine/multitenancy/pom.xml

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
4+
<modelVersion>4.0.0</modelVersion>
5+
<packaging>war</packaging>
6+
<version>1.0-SNAPSHOT</version>
7+
8+
<groupId>com.example.appengine</groupId>
9+
<artifactId>appengine-multitenancy</artifactId>
10+
11+
<properties>
12+
<objectify.version>5.1.5</objectify.version>
13+
<guava.version>18.0</guava.version>
14+
</properties>
15+
<parent>
16+
<groupId>com.google.cloud</groupId>
17+
<artifactId>doc-samples</artifactId>
18+
<version>1.0.0</version>
19+
<relativePath>../..</relativePath>
20+
</parent>
21+
22+
<!-- [START set_versions] -->
23+
<prerequisites>
24+
<maven>3.3.9</maven>
25+
</prerequisites>
26+
<!-- [END set_versions] -->
27+
28+
<dependencies>
29+
<!-- Compile/runtime dependencies -->
30+
<dependency>
31+
<groupId>com.google.appengine</groupId>
32+
<artifactId>appengine-api-1.0-sdk</artifactId>
33+
<version>${appengine.sdk.version}</version>
34+
</dependency>
35+
<dependency>
36+
<groupId>javax.servlet</groupId>
37+
<artifactId>servlet-api</artifactId>
38+
<version>2.5</version>
39+
<scope>provided</scope>
40+
</dependency>
41+
<dependency>
42+
<groupId>jstl</groupId>
43+
<artifactId>jstl</artifactId>
44+
<version>1.2</version>
45+
</dependency>
46+
47+
<!-- [START Objectify_Dependencies] -->
48+
<dependency>
49+
<groupId>com.google.guava</groupId>
50+
<artifactId>guava</artifactId>
51+
<version>${guava.version}</version>
52+
</dependency>
53+
<dependency>
54+
<groupId>com.googlecode.objectify</groupId>
55+
<artifactId>objectify</artifactId>
56+
<version>${objectify.version}</version>
57+
</dependency>
58+
<!-- [END Objectify_Dependencies] -->
59+
60+
<!-- Test Dependencies -->
61+
<dependency>
62+
<groupId>junit</groupId>
63+
<artifactId>junit</artifactId>
64+
<version>4.12</version>
65+
<scope>test</scope>
66+
</dependency>
67+
<dependency>
68+
<groupId>org.mockito</groupId>
69+
<artifactId>mockito-all</artifactId>
70+
<version>1.10.19</version>
71+
<scope>test</scope>
72+
</dependency>
73+
<dependency>
74+
<groupId>com.google.appengine</groupId>
75+
<artifactId>appengine-testing</artifactId>
76+
<version>${appengine.sdk.version}</version>
77+
<scope>test</scope>
78+
</dependency>
79+
<dependency>
80+
<groupId>com.google.appengine</groupId>
81+
<artifactId>appengine-api-stubs</artifactId>
82+
<version>${appengine.sdk.version}</version>
83+
<scope>test</scope>
84+
</dependency>
85+
<dependency>
86+
<groupId>com.google.appengine</groupId>
87+
<artifactId>appengine-tools-sdk</artifactId>
88+
<version>${appengine.sdk.version}</version>
89+
<scope>test</scope>
90+
</dependency>
91+
<dependency>
92+
<groupId>com.google.truth</groupId>
93+
<artifactId>truth</artifactId>
94+
<version>0.28</version>
95+
<scope>test</scope>
96+
</dependency>
97+
98+
</dependencies>
99+
100+
<build>
101+
<!-- for hot reload of the web application-->
102+
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory>
103+
<plugins>
104+
<plugin>
105+
<groupId>com.google.appengine</groupId>
106+
<artifactId>appengine-maven-plugin</artifactId>
107+
<version>${appengine.sdk.version}</version>
108+
<configuration>
109+
<enableJarClasses>false</enableJarClasses>
110+
<!-- Comment in the below snippet to bind to all IPs instead of just localhost -->
111+
<!-- address>0.0.0.0</address>
112+
<port>8080</port -->
113+
<!-- Comment in the below snippet to enable local debugging with a remote debugger
114+
like those included with Eclipse or IntelliJ -->
115+
<!-- jvmFlags>
116+
<jvmFlag>-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n</jvmFlag>
117+
</jvmFlags -->
118+
</configuration>
119+
</plugin>
120+
</plugins>
121+
</build>
122+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/**
2+
* Copyright 2014-2015 Google Inc. All Rights Reserved.
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+
17+
//[START all]
18+
package com.example.appengine;
19+
20+
import com.googlecode.objectify.Key;
21+
import com.googlecode.objectify.annotation.Entity;
22+
import com.googlecode.objectify.annotation.Id;
23+
import com.googlecode.objectify.annotation.Index;
24+
import com.googlecode.objectify.annotation.Parent;
25+
26+
import java.util.Date;
27+
28+
/**
29+
* The @Entity tells Objectify about our entity. We also register it in {@link OfyHelper}
30+
* Our primary key @Id is set automatically by the Google Datastore for us.
31+
*
32+
* We add a @Parent to tell the object about its ancestor. We are doing this to support many
33+
* guestbooks. Objectify, unlike the AppEngine library requires that you specify the fields you
34+
* want to index using @Index. Only indexing the fields you need can lead to substantial gains in
35+
* performance -- though if not indexing your data from the start will require indexing it later.
36+
*
37+
* NOTE - all the properties are PUBLIC so that can keep the code simple.
38+
**/
39+
@Entity
40+
public class Greeting {
41+
@Parent Key<Guestbook> theBook;
42+
@Id public Long id;
43+
44+
public String authorEmail;
45+
public String authorId;
46+
public String content;
47+
@Index public Date date;
48+
49+
/**
50+
* Simple constructor just sets the date.
51+
**/
52+
public Greeting() {
53+
date = new Date();
54+
}
55+
56+
/**
57+
* A convenience constructor.
58+
**/
59+
public Greeting(String book, String content) {
60+
this();
61+
if ( book != null ) {
62+
theBook = Key.create(Guestbook.class, book); // Creating the Ancestor key
63+
} else {
64+
theBook = Key.create(Guestbook.class, "default");
65+
}
66+
this.content = content;
67+
}
68+
69+
public Greeting(String book, String content, String id, String email) {
70+
this(book, content);
71+
authorEmail = email;
72+
authorId = id;
73+
}
74+
75+
}
76+
//[END all]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* Copyright 2014-2015 Google Inc. All Rights Reserved.
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+
17+
//[START all]
18+
package com.example.appengine;
19+
20+
import com.googlecode.objectify.annotation.Entity;
21+
import com.googlecode.objectify.annotation.Id;
22+
23+
/**
24+
* The @Entity tells Objectify about our entity. We also register it in
25+
* OfyHelper.java -- very important.
26+
*
27+
* This is never actually created, but gives a hint to Objectify about our Ancestor key.
28+
*/
29+
@Entity
30+
public class Guestbook {
31+
@Id public String book;
32+
}
33+
//[END all]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Copyright 2016 Google Inc. All Rights Reserved.
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 http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
15+
package com.example.appengine;
16+
17+
import com.google.appengine.api.NamespaceManager;
18+
import com.google.appengine.api.memcache.MemcacheService;
19+
import com.google.appengine.api.memcache.MemcacheServiceFactory;
20+
import com.google.appengine.api.search.Index;
21+
import com.google.appengine.api.search.IndexSpec;
22+
import com.google.appengine.api.search.SearchService;
23+
import com.google.appengine.api.search.SearchServiceConfig;
24+
import com.google.appengine.api.search.SearchServiceFactory;
25+
import com.google.appengine.api.users.UserServiceFactory;
26+
27+
import java.io.IOException;
28+
import java.io.PrintWriter;
29+
30+
import javax.servlet.http.HttpServlet;
31+
import javax.servlet.http.HttpServletRequest;
32+
import javax.servlet.http.HttpServletResponse;
33+
34+
// [START example]
35+
@SuppressWarnings("serial")
36+
public class MultitenancyServlet extends HttpServlet {
37+
38+
@Override
39+
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
40+
String namespace;
41+
42+
PrintWriter out = resp.getWriter();
43+
out.println("Code Snippets -- not yet fully runnable as an app");
44+
45+
// [START temp_namespace]
46+
// Set the namepace temporarily to "abc"
47+
String oldNamespace = NamespaceManager.get();
48+
NamespaceManager.set("abc");
49+
try {
50+
// ... perform operation using current namespace ...
51+
} finally {
52+
NamespaceManager.set(oldNamespace);
53+
}
54+
// [END temp_namespace]
55+
56+
// [START per_user_namespace]
57+
if (com.google.appengine.api.NamespaceManager.get() == null) {
58+
// Assuming there is a logged in user.
59+
namespace = UserServiceFactory.getUserService().getCurrentUser().getUserId();
60+
NamespaceManager.set(namespace);
61+
}
62+
// [END per_user_namespace]
63+
String value = "something here";
64+
65+
// [START ns_memcache]
66+
// Create a MemcacheService that uses the current namespace by
67+
// calling NamespaceManager.get() for every access.
68+
MemcacheService current = MemcacheServiceFactory.getMemcacheService();
69+
70+
// stores value in namespace "abc"
71+
oldNamespace = NamespaceManager.get();
72+
NamespaceManager.set("abc");
73+
try {
74+
current.put("key", value); // stores value in namespace “abc”
75+
} finally {
76+
NamespaceManager.set(oldNamespace);
77+
}
78+
// [END ns_memcache]
79+
80+
// [START specific_memcache]
81+
// Create a MemcacheService that uses the namespace "abc".
82+
MemcacheService explicit = MemcacheServiceFactory.getMemcacheService("abc");
83+
explicit.put("key", value); // stores value in namespace "abc"
84+
// [END specific_memcache]
85+
86+
//[START searchns]
87+
// Set the current namespace to "aSpace"
88+
NamespaceManager.set("aSpace");
89+
// Create a SearchService with the namespace "aSpace"
90+
SearchService searchService = SearchServiceFactory.getSearchService();
91+
// Create an IndexSpec
92+
IndexSpec indexSpec = IndexSpec.newBuilder().setName("myIndex").build();
93+
// Create an Index with the namespace "aSpace"
94+
Index index = searchService.getIndex(indexSpec);
95+
// [END searchns]
96+
97+
// [START searchns_2]
98+
// Create a SearchServiceConfig, specifying the namespace "anotherSpace"
99+
SearchServiceConfig config = SearchServiceConfig.newBuilder()
100+
.setNamespace("anotherSpace").build();
101+
// Create a SearchService with the namespace "anotherSpace"
102+
searchService = SearchServiceFactory.getSearchService(config);
103+
// Create an IndexSpec
104+
indexSpec = IndexSpec.newBuilder().setName("myindex").build();
105+
// Create an Index with the namespace "anotherSpace"
106+
index = searchService.getIndex(indexSpec);
107+
// [END searchns_2]
108+
109+
}
110+
111+
112+
113+
}
114+
// [END example]

0 commit comments

Comments
 (0)