Add a separate object that represents a remote object invocation
[WebKit-https.git] / Source / WebKit2 / Shared / API / Cocoa / _WKRemoteObjectRegistry.mm
1 /*
2  * Copyright (C) 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "_WKRemoteObjectRegistryInternal.h"
28
29 #if WK_API_ENABLED
30
31 #import "APIDictionary.h"
32 #import "Connection.h"
33 #import "RemoteObjectInvocation.h"
34 #import "RemoteObjectRegistry.h"
35 #import "WKConnectionRef.h"
36 #import "WKRemoteObject.h"
37 #import "WKRemoteObjectCoder.h"
38 #import "WKSharedAPICast.h"
39 #import "WebConnection.h"
40 #import "_WKRemoteObjectInterface.h"
41
42 NSString * const invocationKey = @"invocation";
43
44 using namespace WebKit;
45
46 @implementation _WKRemoteObjectRegistry {
47     std::unique_ptr<RemoteObjectRegistry> _remoteObjectRegistry;
48
49     RetainPtr<NSMapTable> _remoteObjectProxies;
50     HashMap<String, std::pair<RetainPtr<id>, RetainPtr<_WKRemoteObjectInterface>>> _exportedObjects;
51 }
52
53 - (void)registerExportedObject:(id)object interface:(_WKRemoteObjectInterface *)interface
54 {
55     ASSERT(!_exportedObjects.contains(interface.identifier));
56     _exportedObjects.add(interface.identifier, std::make_pair<RetainPtr<id>, RetainPtr<_WKRemoteObjectInterface>>(object, interface));
57 }
58
59 - (void)unregisterExportedObject:(id)object interface:(_WKRemoteObjectInterface *)interface
60 {
61     ASSERT(_exportedObjects.get(interface.identifier).first == object);
62     ASSERT(_exportedObjects.get(interface.identifier).second == interface);
63
64     _exportedObjects.remove(interface.identifier);
65 }
66
67 - (id)remoteObjectProxyWithInterface:(_WKRemoteObjectInterface *)interface
68 {
69     if (!_remoteObjectProxies)
70         _remoteObjectProxies = [NSMapTable strongToWeakObjectsMapTable];
71
72     if (id remoteObjectProxy = [_remoteObjectProxies objectForKey:interface.identifier])
73         return remoteObjectProxy;
74
75     RetainPtr<NSString> identifier = adoptNS([interface.identifier copy]);
76     auto remoteObject = adoptNS([[WKRemoteObject alloc] _initWithObjectRegistry:self interface:interface]);
77     [_remoteObjectProxies setObject:remoteObject.get() forKey:identifier.get()];
78
79     return remoteObject.autorelease();
80 }
81
82 - (id)_initWithMessageSender:(IPC::MessageSender&)messageSender
83 {
84     if (!(self = [super init]))
85         return nil;
86
87     _remoteObjectRegistry = std::make_unique<RemoteObjectRegistry>(self, messageSender);
88
89     return self;
90 }
91
92 - (void)_invalidate
93 {
94     _remoteObjectRegistry = nullptr;
95 }
96
97 - (void)_sendInvocation:(NSInvocation *)invocation interface:(_WKRemoteObjectInterface *)interface
98 {
99     auto encoder = adoptNS([[WKRemoteObjectEncoder alloc] init]);
100     [encoder encodeObject:invocation forKey:invocationKey];
101
102     if (!_remoteObjectRegistry)
103         return;
104
105     _remoteObjectRegistry->sendInvocation(RemoteObjectInvocation(interface.identifier, [encoder rootObjectDictionary]));
106 }
107
108 - (WebKit::RemoteObjectRegistry&)remoteObjectRegistry
109 {
110     return *_remoteObjectRegistry;
111 }
112
113 - (BOOL)_invokeMethod:(const RemoteObjectInvocation&)invocation
114 {
115     [self _invokeMessageWithInterfaceIdentifier:invocation.interfaceIdentifier() encodedInvocation:invocation.encodedInvocation()];
116
117     return YES;
118 }
119
120 - (void)_invokeMessageWithInterfaceIdentifier:(const String&)interfaceIdentifier encodedInvocation:(const API::Dictionary*)encodedInvocation
121 {
122     auto interfaceAndObject = _exportedObjects.get(interfaceIdentifier);
123     if (!interfaceAndObject.second) {
124         NSLog(@"Did not find a registered object for the interface \"%@\"", (NSString *)interfaceIdentifier);
125         return;
126     }
127
128     RetainPtr<WKRemoteObjectDecoder> decoder = adoptNS([[WKRemoteObjectDecoder alloc] initWithInterface:interfaceAndObject.second.get() rootObjectDictionary:encodedInvocation]);
129
130     NSInvocation *invocation = nil;
131
132     @try {
133         invocation = [decoder decodeObjectOfClass:[NSInvocation class] forKey:invocationKey];
134     } @catch (NSException *exception) {
135         NSLog(@"Exception caught during decoding of message: %@", exception);
136     }
137
138     invocation.target = interfaceAndObject.first.get();
139
140     @try {
141         [invocation invoke];
142     } @catch (NSException *exception) {
143         NSLog(@"%@: Warning: Exception caught during invocation of received message, dropping incoming message .\nException: %@", self, exception);
144     }
145 }
146
147 @end
148
149 #endif // WK_API_ENABLED