Skip to content
This repository has been archived by the owner on Jun 28, 2022. It is now read-only.

Refactoring PHP generation to use the MVVM pattern #317

Merged
merged 9 commits into from
Jul 28, 2016
4 changes: 2 additions & 2 deletions src/main/java/com/google/api/codegen/ServiceConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
import com.google.api.tools.framework.model.Interface;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

/**
* Utility class that provides service configuration data from an Interface.
Expand Down Expand Up @@ -50,7 +50,7 @@ public String getTitle(Interface service) {
* Return a list of scopes for authentication.
*/
public Iterable<String> getAuthScopes(Interface service) {
Set<String> result = new HashSet<>();
Set<String> result = new TreeSet<>();
Service config = service.getModel().getServiceConfig();
Authentication auth = config.getAuthentication();
for (AuthenticationRule rule : auth.getRulesList()) {
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/google/api/codegen/ServiceMessages.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ public class ServiceMessages {
* Returns true if the message is the empty message.
*/
public boolean isEmptyType(TypeRef type) {
return s_isEmptyType(type);
}

public static boolean s_isEmptyType(TypeRef type) {
return type.isMessage()
&& type.getMessageType().getFullName().equals(Empty.getDescriptor().getFullName());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
package com.google.api.codegen.gapic;

import com.google.api.codegen.ApiConfig;
import com.google.api.codegen.clientconfig.ClientConfigGapicContext;
import com.google.api.codegen.InterfaceListView;
import com.google.api.codegen.InterfaceView;
import com.google.api.codegen.ProtoFileView;
import com.google.api.codegen.SnippetSetRunner;
import com.google.api.codegen.clientconfig.ClientConfigGapicContext;
import com.google.api.codegen.clientconfig.ClientConfigSnippetSetRunner;
import com.google.api.codegen.csharp.CSharpCodePathMapper;
import com.google.api.codegen.csharp.CSharpGapicContext;
Expand All @@ -31,23 +31,24 @@
import com.google.api.codegen.java.JavaSnippetSetRunner;
import com.google.api.codegen.nodejs.NodeJSGapicContext;
import com.google.api.codegen.nodejs.NodeJSSnippetSetRunner;
import com.google.api.codegen.php.PhpGapicContext;
import com.google.api.codegen.php.PhpSnippetSetRunner;
import com.google.api.codegen.py.PythonGapicContext;
import com.google.api.codegen.py.PythonInterfaceInitializer;
import com.google.api.codegen.py.PythonProtoFileInitializer;
import com.google.api.codegen.py.PythonSnippetSetRunner;
import com.google.api.codegen.rendering.CommonSnippetSetRunner;
import com.google.api.codegen.ruby.RubyGapicContext;
import com.google.api.codegen.ruby.RubySnippetSetRunner;
import com.google.api.codegen.transformer.php.PhpGapicSurfaceTransformer;
import com.google.api.codegen.util.CommonRenderingUtil;
import com.google.api.tools.framework.model.Interface;
import com.google.api.tools.framework.model.Model;
import com.google.api.tools.framework.model.ProtoFile;

import org.apache.commons.lang3.NotImplementedException;

import java.util.Arrays;
import java.util.List;

import org.apache.commons.lang3.NotImplementedException;

/**
* MainGapicProviderFactory creates GapicProvider instances based on an id.
*/
Expand Down Expand Up @@ -173,14 +174,11 @@ public static List<GapicProvider<? extends Object>> defaultCreate(
GapicCodePathMapper phpPathMapper =
CommonGapicCodePathMapper.newBuilder().setPrefix("src").build();
GapicProvider<? extends Object> provider =
CommonGapicProvider.<Interface>newBuilder()
ViewModelGapicProvider.newBuilder()
.setModel(model)
.setView(new InterfaceView())
.setContext(new PhpGapicContext(model, apiConfig))
.setSnippetSetRunner(
new PhpSnippetSetRunner<Interface>(SnippetSetRunner.SNIPPET_RESOURCE_ROOT))
.setSnippetFileNames(Arrays.asList("php/main.snip"))
.setCodePathMapper(phpPathMapper)
.setApiConfig(apiConfig)
.setSnippetSetRunner(new CommonSnippetSetRunner(new CommonRenderingUtil()))
.setModelToViewTransformer(new PhpGapicSurfaceTransformer(apiConfig, phpPathMapper))
.build();

GapicCodePathMapper phpClientConfigPathMapper =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/* Copyright 2016 Google Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.api.codegen.gapic;

import com.google.api.codegen.ApiConfig;
import com.google.api.codegen.rendering.CommonSnippetSetRunner;
import com.google.api.codegen.transformer.ModelToViewTransformer;
import com.google.api.codegen.viewmodel.ViewModel;
import com.google.api.tools.framework.model.Interface;
import com.google.api.tools.framework.model.Model;
import com.google.api.tools.framework.model.stages.Merged;
import com.google.api.tools.framework.snippet.Doc;

import java.util.List;
import java.util.Map;
import java.util.TreeMap;

public class ViewModelGapicProvider implements GapicProvider<Interface> {
private final Model model;
private final ApiConfig apiConfig;
private final CommonSnippetSetRunner snippetSetRunner;
private final ModelToViewTransformer modelToViewTransformer;

private ViewModelGapicProvider(
Model model,
ApiConfig apiConfig,
CommonSnippetSetRunner snippetSetRunner,
ModelToViewTransformer modelToViewTransformer) {
this.model = model;
this.apiConfig = apiConfig;
this.snippetSetRunner = snippetSetRunner;
this.modelToViewTransformer = modelToViewTransformer;
}

@Override
public List<String> getSnippetFileNames() {
return modelToViewTransformer.getTemplateFileNames();
}

@Override
public Map<String, Doc> generate() {
return generate(null);
}

@Override
public Map<String, Doc> generate(String snippetFileName) {
// Establish required stage for generation.
model.establishStage(Merged.KEY);
if (model.getDiagCollector().getErrorCount() > 0) {
return null;
}

List<ViewModel> surfaceDocs = modelToViewTransformer.transform(model, apiConfig);
if (model.getDiagCollector().getErrorCount() > 0) {
return null;
}

Map<String, Doc> docs = new TreeMap<>();
for (ViewModel surfaceDoc : surfaceDocs) {
if (snippetFileName != null && !surfaceDoc.templateFileName().equals(snippetFileName)) {
continue;
}
Doc doc = snippetSetRunner.generate(surfaceDoc);
if (doc == null) {
continue;

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

}
docs.put(surfaceDoc.outputPath(), doc);
}

return docs;
}

public static Builder newBuilder() {
return new Builder();
}

public static class Builder {
private Model model;
private ApiConfig apiConfig;
private CommonSnippetSetRunner snippetSetRunner;
private ModelToViewTransformer modelToViewTransformer;

private Builder() {}

public Builder setModel(Model model) {
this.model = model;
return this;
}

public Builder setApiConfig(ApiConfig apiConfig) {
this.apiConfig = apiConfig;
return this;
}

public Builder setSnippetSetRunner(CommonSnippetSetRunner snippetSetRunner) {
this.snippetSetRunner = snippetSetRunner;
return this;
}

public Builder setModelToViewTransformer(ModelToViewTransformer modelToViewTransformer) {
this.modelToViewTransformer = modelToViewTransformer;
return this;
}

public ViewModelGapicProvider build() {
return new ViewModelGapicProvider(model, apiConfig, snippetSetRunner, modelToViewTransformer);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*/
package com.google.api.codegen.metacode;

import com.google.api.codegen.util.Name;
import com.google.api.tools.framework.model.TypeRef;
import com.google.auto.value.AutoValue;

Expand All @@ -25,7 +26,7 @@
public abstract class FieldSetting {

public static FieldSetting create(
TypeRef type, String fieldName, String identifier, InitValueConfig initValueConfig) {
TypeRef type, Name fieldName, Name identifier, InitValueConfig initValueConfig) {
return new AutoValue_FieldSetting(type, fieldName, identifier, initValueConfig);
}

Expand All @@ -37,12 +38,12 @@ public static FieldSetting create(
/**
* Returns the name of the field in the containing structure.
*/
public abstract String getFieldName();
public abstract Name getFieldName();

/**
* Returns the name of the identifier being set on the field.
*/
public abstract String getIdentifier();
public abstract Name getIdentifier();

/**
* Returns the InitValueConfig for the original identifier.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*/
package com.google.api.codegen.metacode;

import com.google.api.codegen.util.Name;
import com.google.api.tools.framework.model.Field;
import com.google.api.tools.framework.model.Method;
import com.google.api.tools.framework.model.TypeRef;
Expand Down Expand Up @@ -44,12 +45,12 @@ public class InitCodeGenerator {
public InitCode generateRequestObjectInitCode(
Method method, Map<String, Object> initFieldStructure) {
InitCodeLine lastLine =
generateSampleCodeInit("request", method.getInputType(), initFieldStructure);
generateSampleCodeInit(Name.from("request"), method.getInputType(), initFieldStructure);
initLineSpecs.add(lastLine);
FieldSetting requestField =
FieldSetting.create(
method.getInputType(),
"request",
Name.from("request"),
lastLine.getIdentifier(),
lastLine.getInitValueConfig());
List<FieldSetting> outputFields = Arrays.asList(requestField);
Expand All @@ -73,7 +74,8 @@ public InitCode generateRequestFieldInitCode(
}
}

InitCodeLine lastLine = generateSampleCodeInit("request", method.getInputType(), filteredInit);
InitCodeLine lastLine =
generateSampleCodeInit(Name.from("request"), method.getInputType(), filteredInit);
if (!(lastLine instanceof StructureInitCodeLine)) {
throw new IllegalArgumentException(
"Expected method request to be a message, found " + lastLine.getClass().getName());
Expand All @@ -82,18 +84,18 @@ public InitCode generateRequestFieldInitCode(
return InitCode.create(initLineSpecs, requestInitCodeLine.getFieldSettings());
}

private String getNewSymbol(String desiredName) {
String actualName = desiredName;
private Name getNewSymbol(Name desiredName) {
Name actualName = desiredName;
int i = 2;
while (symbolTable.contains(actualName)) {
actualName = desiredName + i;
while (symbolTable.contains(actualName.toLowerUnderscore())) {
actualName = desiredName.join(Integer.toString(i));
}
symbolTable.add(actualName);
symbolTable.add(actualName.toLowerUnderscore());
return actualName;
}

private InitCodeLine generateSampleCodeInitStructure(
String suggestedName, TypeRef typeRef, Map<String, Object> initFieldMap) {
Name suggestedName, TypeRef typeRef, Map<String, Object> initFieldMap) {
List<FieldSetting> fieldSettings = new ArrayList<>();
for (Field field : typeRef.getMessageType().getFields()) {
Object thisFieldInitStructure = initFieldMap.get(field.getSimpleName());
Expand All @@ -102,13 +104,14 @@ private InitCodeLine generateSampleCodeInitStructure(
}

InitCodeLine subFieldInit =
generateSampleCodeInit(field.getSimpleName(), field.getType(), thisFieldInitStructure);
generateSampleCodeInit(
Name.from(field.getSimpleName()), field.getType(), thisFieldInitStructure);
initLineSpecs.add(subFieldInit);

FieldSetting fieldSetting =
FieldSetting.create(
field.getType(),
field.getSimpleName(),
Name.from(field.getSimpleName()),
subFieldInit.getIdentifier(),
subFieldInit.getInitValueConfig());
fieldSettings.add(fieldSetting);
Expand All @@ -119,15 +122,15 @@ private InitCodeLine generateSampleCodeInitStructure(

// get a new symbol for this object after subfields, in order to preserve
// numerical ordering in the case of conflicts
String identifier = getNewSymbol(suggestedName);
Name identifier = getNewSymbol(suggestedName);
return StructureInitCodeLine.create(typeRef, identifier, fieldSettings);
}

private InitCodeLine generateSampleCodeInitList(
String suggestedName, TypeRef typeRef, List<Object> thisFieldInitList) {
List<String> elementIdentifiers = new ArrayList<>();
Name suggestedName, TypeRef typeRef, List<Object> thisFieldInitList) {
List<Name> elementIdentifiers = new ArrayList<>();
for (Object elementInitStructure : thisFieldInitList) {
String suggestedElementName = suggestedName + "_element";
Name suggestedElementName = suggestedName.join("element");
// Using the Optional cardinality replaces the Repeated cardinality
TypeRef elementType = typeRef.makeOptional();
InitCodeLine subFieldInit =
Expand All @@ -139,15 +142,15 @@ private InitCodeLine generateSampleCodeInitList(

// get a new symbol for this object after elements, in order to preserve
// numerical ordering in the case of conflicts
String identifier = getNewSymbol(suggestedName);
Name identifier = getNewSymbol(suggestedName);
return ListInitCodeLine.create(typeRef, identifier, elementIdentifiers);
}

private InitCodeLine generateSampleCodeInitMap(
String suggestedName, TypeRef typeRef, Map<String, Object> thisFieldInitMap) {
Name suggestedName, TypeRef typeRef, Map<String, Object> thisFieldInitMap) {
TypeRef keyTypeRef = typeRef.getMapKeyField().getType();
TypeRef elementType = typeRef.getMapValueField().getType();
Map<String, String> elementIdentifierMap = new HashMap<String, String>();
Map<String, Name> elementIdentifierMap = new HashMap<>();
for (String keyString : thisFieldInitMap.keySet()) {
String validatedKeyString = validateValue(keyTypeRef, keyString);
if (validatedKeyString == null) {
Expand All @@ -163,7 +166,7 @@ private InitCodeLine generateSampleCodeInitMap(
}

Object elementInitStructure = thisFieldInitMap.get(keyString);
String suggestedElementName = suggestedName + "_item";
Name suggestedElementName = suggestedName.join("item");
InitCodeLine subFieldInit =
generateSampleCodeInit(suggestedElementName, elementType, elementInitStructure);
initLineSpecs.add(subFieldInit);
Expand All @@ -173,19 +176,19 @@ private InitCodeLine generateSampleCodeInitMap(

// get a new symbol for this object after elements, in order to preserve
// numerical ordering in the case of conflicts
String identifier = getNewSymbol(suggestedName);
Name identifier = getNewSymbol(suggestedName);
return MapInitCodeLine.create(
keyTypeRef, elementType, typeRef, identifier, elementIdentifierMap);
}

private InitCodeLine generateSampleCodeInit(
String suggestedName, TypeRef typeRef, Object initFieldStructure) {
Name suggestedName, TypeRef typeRef, Object initFieldStructure) {
// No matter what the type in the model is, we want to stop here, because we
// have reached the end of initFieldStructure. At codegen time, we will
// generate the zero value for the type.
if (initFieldStructure instanceof InitValueConfig) {
InitValueConfig initValueConfig = (InitValueConfig) initFieldStructure;
String identifier = getNewSymbol(suggestedName);
Name identifier = getNewSymbol(suggestedName);
if (initValueConfig.hasInitialValue()) {
String validatedValue = validateValue(typeRef, initValueConfig.getInitialValue());
if (validatedValue == null) {
Expand Down
Loading